From 3f1fff6d96fbdf6e156b49e33b88075bba21629e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Sat, 26 May 2018 20:44:06 +0200 Subject: [PATCH 001/263] Implementation of a new Dagger injection (#103) --- .../io/github/wulkanowy/WulkanowyApp.java | 23 ++-- .../wulkanowy/data/db/dao/DbHelper.java | 5 +- .../db/resources/ResourcesRepository.java | 3 +- .../data/db/shared/SharedPrefRepository.java | 5 +- .../wulkanowy/data/sync/AccountSync.java | 3 +- .../io/github/wulkanowy/di/AppComponent.java | 20 ++++ .../io/github/wulkanowy/di/AppModule.java | 78 ++++++++++++ .../io/github/wulkanowy/di/BuilderModule.java | 39 ++++++ .../di/annotations/ActivityContext.java | 11 -- .../di/annotations/ApplicationContext.java | 11 -- .../di/annotations/SharedPreferencesInfo.java | 11 -- .../di/component/ActivityComponent.java | 19 --- .../di/component/ApplicationComponent.java | 32 ----- .../di/component/FragmentComponent.java | 31 ----- .../wulkanowy/di/modules/ActivityModule.java | 64 ---------- .../di/modules/ApplicationModule.java | 111 ------------------ .../wulkanowy/di/modules/FragmentModule.java | 103 ---------------- .../{annotations => scopes}/PerActivity.java | 2 +- .../PerChildFragment.java} | 8 +- .../{annotations => scopes}/PerFragment.java | 2 +- .../wulkanowy/services/jobs/SyncJob.java | 4 +- .../widgets/TimetableWidgetServices.java | 10 +- .../wulkanowy/ui/base/BaseActivity.java | 72 +++++------- .../wulkanowy/ui/base/BaseContract.java | 15 +-- .../wulkanowy/ui/base/BaseFragment.java | 100 ++++------------ .../wulkanowy/ui/base/BasePresenter.java | 6 +- .../wulkanowy/ui/login/LoginActivity.java | 29 ++--- .../wulkanowy/ui/login/LoginContract.java | 5 - .../wulkanowy/ui/login/LoginModule.java | 13 ++ .../wulkanowy/ui/login/LoginPresenter.java | 8 +- .../wulkanowy/ui/main/MainActivity.java | 18 ++- .../wulkanowy/ui/main/MainContract.java | 6 +- .../github/wulkanowy/ui/main/MainModule.java | 50 ++++++++ .../wulkanowy/ui/main/MainPresenter.java | 10 +- .../main/attendance/AttendanceContract.java | 6 +- .../main/attendance/AttendanceFragment.java | 29 ++--- .../ui/main/attendance/AttendanceModule.java | 32 +++++ .../main/attendance/AttendancePresenter.java | 13 +- .../{ => tab}/AttendanceHeaderItem.java | 2 +- .../{ => tab}/AttendanceSubItem.java | 3 +- .../{ => tab}/AttendanceTabContract.java | 2 +- .../{ => tab}/AttendanceTabFragment.java | 39 ++---- .../attendance/tab/AttendanceTabModule.java | 21 ++++ .../{ => tab}/AttendanceTabPresenter.java | 17 +-- .../ui/main/exams/ExamsContract.java | 6 +- .../ui/main/exams/ExamsFragment.java | 26 ++-- .../wulkanowy/ui/main/exams/ExamsModule.java | 32 +++++ .../ui/main/exams/ExamsPresenter.java | 12 +- .../main/exams/{ => tab}/ExamsHeaderItem.java | 4 +- .../ui/main/exams/{ => tab}/ExamsSubItem.java | 3 +- .../exams/{ => tab}/ExamsTabContract.java | 4 +- .../exams/{ => tab}/ExamsTabFragment.java | 35 ++---- .../ui/main/exams/tab/ExamsTabModule.java | 21 ++++ .../exams/{ => tab}/ExamsTabPresenter.java | 18 +-- .../ui/main/grades/GradesContract.java | 5 +- .../ui/main/grades/GradesFragment.java | 30 ++--- .../ui/main/grades/GradesModule.java | 18 +++ .../ui/main/grades/GradesPresenter.java | 14 ++- .../ui/main/timetable/TimetableContract.java | 6 +- .../ui/main/timetable/TimetableFragment.java | 27 ++--- .../ui/main/timetable/TimetableModule.java | 32 +++++ .../ui/main/timetable/TimetablePresenter.java | 12 +- .../{ => tab}/TimetableHeaderItem.java | 2 +- .../timetable/{ => tab}/TimetableSubItem.java | 3 +- .../{ => tab}/TimetableTabContract.java | 2 +- .../{ => tab}/TimetableTabFragment.java | 36 ++---- .../timetable/tab/TimetableTabModule.java | 21 ++++ .../{ => tab}/TimetableTabPresenter.java | 17 +-- .../wulkanowy/ui/splash/SplashActivity.java | 10 +- .../wulkanowy/ui/splash/SplashContract.java | 3 - .../wulkanowy/ui/splash/SplashModule.java | 13 ++ .../wulkanowy/ui/splash/SplashPresenter.java | 4 +- .../ui/widgets/TimetableWidgetFactory.java | 17 +-- .../ui/widgets/TimetableWidgetProvider.java | 5 +- 74 files changed, 678 insertions(+), 851 deletions(-) create mode 100644 app/src/main/java/io/github/wulkanowy/di/AppComponent.java create mode 100644 app/src/main/java/io/github/wulkanowy/di/AppModule.java create mode 100644 app/src/main/java/io/github/wulkanowy/di/BuilderModule.java delete mode 100644 app/src/main/java/io/github/wulkanowy/di/annotations/ActivityContext.java delete mode 100644 app/src/main/java/io/github/wulkanowy/di/annotations/ApplicationContext.java delete mode 100644 app/src/main/java/io/github/wulkanowy/di/annotations/SharedPreferencesInfo.java delete mode 100644 app/src/main/java/io/github/wulkanowy/di/component/ActivityComponent.java delete mode 100644 app/src/main/java/io/github/wulkanowy/di/component/ApplicationComponent.java delete mode 100644 app/src/main/java/io/github/wulkanowy/di/component/FragmentComponent.java delete mode 100644 app/src/main/java/io/github/wulkanowy/di/modules/ActivityModule.java delete mode 100644 app/src/main/java/io/github/wulkanowy/di/modules/ApplicationModule.java delete mode 100644 app/src/main/java/io/github/wulkanowy/di/modules/FragmentModule.java rename app/src/main/java/io/github/wulkanowy/di/{annotations => scopes}/PerActivity.java (81%) rename app/src/main/java/io/github/wulkanowy/di/{annotations/DatabaseInfo.java => scopes/PerChildFragment.java} (51%) rename app/src/main/java/io/github/wulkanowy/di/{annotations => scopes}/PerFragment.java (81%) create mode 100644 app/src/main/java/io/github/wulkanowy/ui/login/LoginModule.java create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/MainModule.java create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceModule.java rename app/src/main/java/io/github/wulkanowy/ui/main/attendance/{ => tab}/AttendanceHeaderItem.java (99%) rename app/src/main/java/io/github/wulkanowy/ui/main/attendance/{ => tab}/AttendanceSubItem.java (96%) rename app/src/main/java/io/github/wulkanowy/ui/main/attendance/{ => tab}/AttendanceTabContract.java (92%) rename app/src/main/java/io/github/wulkanowy/ui/main/attendance/{ => tab}/AttendanceTabFragment.java (76%) create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabModule.java rename app/src/main/java/io/github/wulkanowy/ui/main/attendance/{ => tab}/AttendanceTabPresenter.java (92%) create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsModule.java rename app/src/main/java/io/github/wulkanowy/ui/main/exams/{ => tab}/ExamsHeaderItem.java (96%) rename app/src/main/java/io/github/wulkanowy/ui/main/exams/{ => tab}/ExamsSubItem.java (96%) rename app/src/main/java/io/github/wulkanowy/ui/main/exams/{ => tab}/ExamsTabContract.java (83%) rename app/src/main/java/io/github/wulkanowy/ui/main/exams/{ => tab}/ExamsTabFragment.java (74%) create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabModule.java rename app/src/main/java/io/github/wulkanowy/ui/main/exams/{ => tab}/ExamsTabPresenter.java (90%) create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesModule.java create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableModule.java rename app/src/main/java/io/github/wulkanowy/ui/main/timetable/{ => tab}/TimetableHeaderItem.java (98%) rename app/src/main/java/io/github/wulkanowy/ui/main/timetable/{ => tab}/TimetableSubItem.java (97%) rename app/src/main/java/io/github/wulkanowy/ui/main/timetable/{ => tab}/TimetableTabContract.java (92%) rename app/src/main/java/io/github/wulkanowy/ui/main/timetable/{ => tab}/TimetableTabFragment.java (78%) create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabModule.java rename app/src/main/java/io/github/wulkanowy/ui/main/timetable/{ => tab}/TimetableTabPresenter.java (92%) create mode 100644 app/src/main/java/io/github/wulkanowy/ui/splash/SplashModule.java diff --git a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java index 2ecc51090..5b68abbf4 100644 --- a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java +++ b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java @@ -1,7 +1,5 @@ package io.github.wulkanowy; -import android.app.Application; - import com.crashlytics.android.Crashlytics; import com.crashlytics.android.answers.Answers; import com.crashlytics.android.core.CrashlyticsCore; @@ -11,18 +9,16 @@ import org.greenrobot.greendao.query.QueryBuilder; import javax.inject.Inject; +import dagger.android.AndroidInjector; +import dagger.android.support.DaggerApplication; import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.utils.Log; import io.fabric.sdk.android.Fabric; import io.github.wulkanowy.data.RepositoryContract; -import io.github.wulkanowy.di.component.ApplicationComponent; -import io.github.wulkanowy.di.component.DaggerApplicationComponent; -import io.github.wulkanowy.di.modules.ApplicationModule; +import io.github.wulkanowy.di.DaggerAppComponent; import io.github.wulkanowy.utils.LogUtils; -public class WulkanowyApp extends Application { - - protected ApplicationComponent applicationComponent; +public class WulkanowyApp extends DaggerApplication { @Inject RepositoryContract repository; @@ -32,12 +28,6 @@ public class WulkanowyApp extends Application { super.onCreate(); AndroidThreeTen.init(this); - applicationComponent = DaggerApplicationComponent - .builder() - .applicationModule(new ApplicationModule(this)) - .build(); - applicationComponent.inject(this); - if (BuildConfig.DEBUG) { enableDebugLog(); } @@ -72,7 +62,8 @@ public class WulkanowyApp extends Application { .build()); } - public ApplicationComponent getApplicationComponent() { - return applicationComponent; + @Override + protected AndroidInjector applicationInjector() { + return DaggerAppComponent.builder().create(this); } } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java index 97bb75598..7ffcfe279 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java @@ -12,6 +12,7 @@ import java.util.Comparator; import java.util.List; import javax.inject.Inject; +import javax.inject.Named; import javax.inject.Singleton; import io.github.wulkanowy.api.Vulcan; @@ -21,8 +22,6 @@ import io.github.wulkanowy.data.db.dao.migrations.Migration26; import io.github.wulkanowy.data.db.dao.migrations.Migration27; import io.github.wulkanowy.data.db.dao.migrations.Migration28; import io.github.wulkanowy.data.db.shared.SharedPrefContract; -import io.github.wulkanowy.di.annotations.ApplicationContext; -import io.github.wulkanowy.di.annotations.DatabaseInfo; import io.github.wulkanowy.utils.LogUtils; @Singleton @@ -33,7 +32,7 @@ public class DbHelper extends DaoMaster.OpenHelper { private final Vulcan vulcan; @Inject - DbHelper(@ApplicationContext Context context, @DatabaseInfo String dbName, + DbHelper(Context context, @Named("dbName") String dbName, SharedPrefContract sharedPref, Vulcan vulcan) { super(context, dbName); this.sharedPref = sharedPref; diff --git a/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java b/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java index a430e3355..81aeaee2b 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java @@ -15,7 +15,6 @@ import javax.inject.Singleton; import io.github.wulkanowy.R; import io.github.wulkanowy.api.NotLoggedInErrorException; import io.github.wulkanowy.data.db.dao.entities.AttendanceLesson; -import io.github.wulkanowy.di.annotations.ApplicationContext; import io.github.wulkanowy.utils.AppConstant; import io.github.wulkanowy.utils.LogUtils; import io.github.wulkanowy.utils.security.CryptoException; @@ -26,7 +25,7 @@ public class ResourcesRepository implements ResourcesContract { private Resources resources; @Inject - ResourcesRepository(@ApplicationContext Context context) { + ResourcesRepository(Context context) { resources = context.getResources(); } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefRepository.java b/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefRepository.java index bf46ce35a..11f43ca38 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefRepository.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefRepository.java @@ -6,10 +6,9 @@ import android.content.SharedPreferences; import android.preference.PreferenceManager; import javax.inject.Inject; +import javax.inject.Named; import javax.inject.Singleton; -import io.github.wulkanowy.di.annotations.ApplicationContext; -import io.github.wulkanowy.di.annotations.SharedPreferencesInfo; import io.github.wulkanowy.ui.main.settings.SettingsFragment; @Singleton @@ -24,7 +23,7 @@ public class SharedPrefRepository implements SharedPrefContract { private final SharedPreferences settingsSharedPref; @Inject - SharedPrefRepository(@ApplicationContext Context context, @SharedPreferencesInfo String sharedName) { + SharedPrefRepository(Context context, @Named("sharedPrefName") String sharedName) { appSharedPref = context.getSharedPreferences(sharedName, Context.MODE_PRIVATE); settingsSharedPref = PreferenceManager.getDefaultSharedPreferences(context); } diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java index 27b497c78..032e95e4e 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java @@ -23,7 +23,6 @@ import io.github.wulkanowy.data.db.dao.entities.StudentDao; import io.github.wulkanowy.data.db.dao.entities.Symbol; import io.github.wulkanowy.data.db.dao.entities.SymbolDao; import io.github.wulkanowy.data.db.shared.SharedPrefContract; -import io.github.wulkanowy.di.annotations.ApplicationContext; import io.github.wulkanowy.utils.DataObjectConverter; import io.github.wulkanowy.utils.LogUtils; import io.github.wulkanowy.utils.security.CryptoException; @@ -42,7 +41,7 @@ public class AccountSync { @Inject AccountSync(DaoSession daoSession, SharedPrefContract sharedPref, - Vulcan vulcan, @ApplicationContext Context context) { + Vulcan vulcan, Context context) { this.daoSession = daoSession; this.sharedPref = sharedPref; this.vulcan = vulcan; diff --git a/app/src/main/java/io/github/wulkanowy/di/AppComponent.java b/app/src/main/java/io/github/wulkanowy/di/AppComponent.java new file mode 100644 index 000000000..92f5d9a19 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/di/AppComponent.java @@ -0,0 +1,20 @@ +package io.github.wulkanowy.di; + +import javax.inject.Singleton; + +import dagger.Component; +import dagger.android.AndroidInjector; +import dagger.android.support.AndroidSupportInjectionModule; +import io.github.wulkanowy.WulkanowyApp; + +@Singleton +@Component(modules = { + AndroidSupportInjectionModule.class, + AppModule.class, + BuilderModule.class +}) +public interface AppComponent extends AndroidInjector { + @Component.Builder + abstract class Builder extends AndroidInjector.Builder { + } +} diff --git a/app/src/main/java/io/github/wulkanowy/di/AppModule.java b/app/src/main/java/io/github/wulkanowy/di/AppModule.java new file mode 100644 index 000000000..d6d4dfa2f --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/di/AppModule.java @@ -0,0 +1,78 @@ +package io.github.wulkanowy.di; + +import android.content.Context; + +import javax.inject.Named; +import javax.inject.Singleton; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; +import io.github.wulkanowy.WulkanowyApp; +import io.github.wulkanowy.api.Vulcan; +import io.github.wulkanowy.data.Repository; +import io.github.wulkanowy.data.RepositoryContract; +import io.github.wulkanowy.data.db.dao.DbContract; +import io.github.wulkanowy.data.db.dao.DbHelper; +import io.github.wulkanowy.data.db.dao.DbRepository; +import io.github.wulkanowy.data.db.dao.entities.DaoMaster; +import io.github.wulkanowy.data.db.dao.entities.DaoSession; +import io.github.wulkanowy.data.db.resources.ResourcesContract; +import io.github.wulkanowy.data.db.resources.ResourcesRepository; +import io.github.wulkanowy.data.db.shared.SharedPrefContract; +import io.github.wulkanowy.data.db.shared.SharedPrefRepository; +import io.github.wulkanowy.data.sync.SyncContract; +import io.github.wulkanowy.data.sync.SyncRepository; +import io.github.wulkanowy.utils.AppConstant; + +@Module +public abstract class AppModule { + + @Binds + abstract Context provideContext(WulkanowyApp app); + + @Singleton + @Binds + abstract RepositoryContract provideRepository(Repository repository); + + @Singleton + @Binds + abstract DbContract provideDatabse(DbRepository dbRepository); + + @Singleton + @Binds + abstract SharedPrefContract provideSharedPref(SharedPrefRepository sharedPrefRepository); + + @Singleton + @Binds + abstract SyncContract provideSync(SyncRepository syncRepository); + + @Singleton + @Binds + abstract ResourcesContract provideResources(ResourcesRepository resourcesRepository); + + @Singleton + @Provides + static DaoSession provideDaoSession(DbHelper dbHelper) { + return new DaoMaster(dbHelper.getWritableDb()).newSession(); + } + + @Singleton + @Provides + static Vulcan provideVulcan() { + return new Vulcan(); + } + + @Provides + @Named("dbName") + static String provideDbName() { + return AppConstant.DATABASE_NAME; + } + + @Provides + @Named("sharedPrefName") + static String provideSharedPrefName() { + return AppConstant.SHARED_PREFERENCES_NAME; + } + +} diff --git a/app/src/main/java/io/github/wulkanowy/di/BuilderModule.java b/app/src/main/java/io/github/wulkanowy/di/BuilderModule.java new file mode 100644 index 000000000..74b77d520 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/di/BuilderModule.java @@ -0,0 +1,39 @@ +package io.github.wulkanowy.di; + +import dagger.Module; +import dagger.android.ContributesAndroidInjector; +import io.github.wulkanowy.di.scopes.PerActivity; +import io.github.wulkanowy.services.jobs.SyncJob; +import io.github.wulkanowy.services.widgets.TimetableWidgetServices; +import io.github.wulkanowy.ui.login.LoginActivity; +import io.github.wulkanowy.ui.login.LoginModule; +import io.github.wulkanowy.ui.main.MainActivity; +import io.github.wulkanowy.ui.main.MainModule; +import io.github.wulkanowy.ui.splash.SplashActivity; +import io.github.wulkanowy.ui.splash.SplashModule; +import io.github.wulkanowy.ui.widgets.TimetableWidgetProvider; + +@Module +abstract class BuilderModule { + + @PerActivity + @ContributesAndroidInjector(modules = SplashModule.class) + abstract SplashActivity bindSplashActivity(); + + @PerActivity + @ContributesAndroidInjector(modules = LoginModule.class) + abstract LoginActivity bindLoginActivity(); + + @PerActivity + @ContributesAndroidInjector(modules = MainModule.class) + abstract MainActivity bindMainActivity(); + + @ContributesAndroidInjector + abstract SyncJob bindSyncJob(); + + @ContributesAndroidInjector + abstract TimetableWidgetServices bindTimetableWidgetServices(); + + @ContributesAndroidInjector + abstract TimetableWidgetProvider bindTimetableWidgetProvider(); +} diff --git a/app/src/main/java/io/github/wulkanowy/di/annotations/ActivityContext.java b/app/src/main/java/io/github/wulkanowy/di/annotations/ActivityContext.java deleted file mode 100644 index 2a74c32d3..000000000 --- a/app/src/main/java/io/github/wulkanowy/di/annotations/ActivityContext.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.github.wulkanowy.di.annotations; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.inject.Qualifier; - -@Qualifier -@Retention(RetentionPolicy.RUNTIME) -public @interface ActivityContext { -} diff --git a/app/src/main/java/io/github/wulkanowy/di/annotations/ApplicationContext.java b/app/src/main/java/io/github/wulkanowy/di/annotations/ApplicationContext.java deleted file mode 100644 index 04139d998..000000000 --- a/app/src/main/java/io/github/wulkanowy/di/annotations/ApplicationContext.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.github.wulkanowy.di.annotations; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.inject.Qualifier; - -@Qualifier -@Retention(RetentionPolicy.RUNTIME) -public @interface ApplicationContext { -} diff --git a/app/src/main/java/io/github/wulkanowy/di/annotations/SharedPreferencesInfo.java b/app/src/main/java/io/github/wulkanowy/di/annotations/SharedPreferencesInfo.java deleted file mode 100644 index 919c77a0b..000000000 --- a/app/src/main/java/io/github/wulkanowy/di/annotations/SharedPreferencesInfo.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.github.wulkanowy.di.annotations; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import javax.inject.Qualifier; - -@Qualifier -@Retention(RetentionPolicy.RUNTIME) -public @interface SharedPreferencesInfo { -} diff --git a/app/src/main/java/io/github/wulkanowy/di/component/ActivityComponent.java b/app/src/main/java/io/github/wulkanowy/di/component/ActivityComponent.java deleted file mode 100644 index 3365a317e..000000000 --- a/app/src/main/java/io/github/wulkanowy/di/component/ActivityComponent.java +++ /dev/null @@ -1,19 +0,0 @@ -package io.github.wulkanowy.di.component; - -import dagger.Component; -import io.github.wulkanowy.di.annotations.PerActivity; -import io.github.wulkanowy.di.modules.ActivityModule; -import io.github.wulkanowy.ui.login.LoginActivity; -import io.github.wulkanowy.ui.main.MainActivity; -import io.github.wulkanowy.ui.splash.SplashActivity; - -@PerActivity -@Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) -public interface ActivityComponent { - - void inject(SplashActivity splashActivity); - - void inject(LoginActivity loginActivity); - - void inject(MainActivity mainActivity); -} diff --git a/app/src/main/java/io/github/wulkanowy/di/component/ApplicationComponent.java b/app/src/main/java/io/github/wulkanowy/di/component/ApplicationComponent.java deleted file mode 100644 index d4bf7bb77..000000000 --- a/app/src/main/java/io/github/wulkanowy/di/component/ApplicationComponent.java +++ /dev/null @@ -1,32 +0,0 @@ -package io.github.wulkanowy.di.component; - -import android.content.Context; - -import javax.inject.Singleton; - -import dagger.Component; -import io.github.wulkanowy.WulkanowyApp; -import io.github.wulkanowy.data.RepositoryContract; -import io.github.wulkanowy.di.annotations.ApplicationContext; -import io.github.wulkanowy.di.modules.ApplicationModule; -import io.github.wulkanowy.services.jobs.SyncJob; -import io.github.wulkanowy.ui.widgets.TimetableWidgetFactory; -import io.github.wulkanowy.ui.widgets.TimetableWidgetProvider; - -@Singleton -@Component(modules = ApplicationModule.class) -public interface ApplicationComponent { - - @ApplicationContext - Context getContext(); - - RepositoryContract getRepository(); - - void inject(WulkanowyApp wulkanowyApp); - - void inject(SyncJob syncJob); - - void inject(TimetableWidgetFactory timetableWidgetFactory); - - void inject(TimetableWidgetProvider timetableWidgetProvider); -} diff --git a/app/src/main/java/io/github/wulkanowy/di/component/FragmentComponent.java b/app/src/main/java/io/github/wulkanowy/di/component/FragmentComponent.java deleted file mode 100644 index 9f56364c4..000000000 --- a/app/src/main/java/io/github/wulkanowy/di/component/FragmentComponent.java +++ /dev/null @@ -1,31 +0,0 @@ -package io.github.wulkanowy.di.component; - -import dagger.Component; -import io.github.wulkanowy.di.annotations.PerFragment; -import io.github.wulkanowy.di.modules.FragmentModule; -import io.github.wulkanowy.ui.main.attendance.AttendanceFragment; -import io.github.wulkanowy.ui.main.attendance.AttendanceTabFragment; -import io.github.wulkanowy.ui.main.exams.ExamsFragment; -import io.github.wulkanowy.ui.main.exams.ExamsTabFragment; -import io.github.wulkanowy.ui.main.grades.GradesFragment; -import io.github.wulkanowy.ui.main.timetable.TimetableFragment; -import io.github.wulkanowy.ui.main.timetable.TimetableTabFragment; - -@PerFragment -@Component(dependencies = ApplicationComponent.class, modules = FragmentModule.class) -public interface FragmentComponent { - - void inject(GradesFragment gradesFragment); - - void inject(AttendanceFragment attendanceFragment); - - void inject(AttendanceTabFragment attendanceTabFragment); - - void inject(ExamsFragment examsFragment); - - void inject(ExamsTabFragment examsTabFragment); - - void inject(TimetableFragment timetableFragment); - - void inject(TimetableTabFragment timetableTabFragment); -} diff --git a/app/src/main/java/io/github/wulkanowy/di/modules/ActivityModule.java b/app/src/main/java/io/github/wulkanowy/di/modules/ActivityModule.java deleted file mode 100644 index cdffe73a1..000000000 --- a/app/src/main/java/io/github/wulkanowy/di/modules/ActivityModule.java +++ /dev/null @@ -1,64 +0,0 @@ -package io.github.wulkanowy.di.modules; - - -import android.content.Context; -import android.support.v7.app.AppCompatActivity; - -import dagger.Module; -import dagger.Provides; -import io.github.wulkanowy.di.annotations.ActivityContext; -import io.github.wulkanowy.di.annotations.PerActivity; -import io.github.wulkanowy.ui.base.BasePagerAdapter; -import io.github.wulkanowy.ui.login.LoginContract; -import io.github.wulkanowy.ui.login.LoginPresenter; -import io.github.wulkanowy.ui.main.MainContract; -import io.github.wulkanowy.ui.main.MainPresenter; -import io.github.wulkanowy.ui.splash.SplashContract; -import io.github.wulkanowy.ui.splash.SplashPresenter; - -@Module -public class ActivityModule { - - private AppCompatActivity activity; - - public ActivityModule(AppCompatActivity activity) { - this.activity = activity; - } - - @ActivityContext - @Provides - Context provideContext() { - return activity; - } - - @Provides - AppCompatActivity provideActivity() { - return activity; - } - - @PerActivity - @Provides - SplashContract.Presenter provideSplashPresenter - (SplashPresenter splashPresenter) { - return splashPresenter; - } - - @PerActivity - @Provides - LoginContract.Presenter provideLoginPresenter - (LoginPresenter loginPresenter) { - return loginPresenter; - } - - @PerActivity - @Provides - MainContract.Presenter provideMainPresenter - (MainPresenter mainPresenter) { - return mainPresenter; - } - - @Provides - BasePagerAdapter provideMainPagerAdapter() { - return new BasePagerAdapter(activity.getSupportFragmentManager()); - } -} diff --git a/app/src/main/java/io/github/wulkanowy/di/modules/ApplicationModule.java b/app/src/main/java/io/github/wulkanowy/di/modules/ApplicationModule.java deleted file mode 100644 index 7c2b39849..000000000 --- a/app/src/main/java/io/github/wulkanowy/di/modules/ApplicationModule.java +++ /dev/null @@ -1,111 +0,0 @@ -package io.github.wulkanowy.di.modules; - -import android.app.Application; -import android.content.Context; - -import com.firebase.jobdispatcher.FirebaseJobDispatcher; -import com.firebase.jobdispatcher.GooglePlayDriver; - -import javax.inject.Singleton; - -import dagger.Module; -import dagger.Provides; -import io.github.wulkanowy.api.Vulcan; -import io.github.wulkanowy.data.Repository; -import io.github.wulkanowy.data.RepositoryContract; -import io.github.wulkanowy.data.db.dao.DbContract; -import io.github.wulkanowy.data.db.dao.DbHelper; -import io.github.wulkanowy.data.db.dao.DbRepository; -import io.github.wulkanowy.data.db.dao.entities.DaoMaster; -import io.github.wulkanowy.data.db.dao.entities.DaoSession; -import io.github.wulkanowy.data.db.resources.ResourcesContract; -import io.github.wulkanowy.data.db.resources.ResourcesRepository; -import io.github.wulkanowy.data.db.shared.SharedPrefContract; -import io.github.wulkanowy.data.db.shared.SharedPrefRepository; -import io.github.wulkanowy.data.sync.SyncContract; -import io.github.wulkanowy.data.sync.SyncRepository; -import io.github.wulkanowy.di.annotations.ApplicationContext; -import io.github.wulkanowy.di.annotations.DatabaseInfo; -import io.github.wulkanowy.di.annotations.SharedPreferencesInfo; -import io.github.wulkanowy.utils.AppConstant; - -@Module -public class ApplicationModule { - - private final Application application; - - public ApplicationModule(Application application) { - this.application = application; - } - - @Provides - Application provideApplication() { - return application; - } - - @ApplicationContext - @Provides - Context provideAppContext() { - return application; - } - - @DatabaseInfo - @Provides - String provideDatabaseName() { - return AppConstant.DATABASE_NAME; - } - - @SharedPreferencesInfo - @Provides - String provideSharedPreferencesName() { - return AppConstant.SHARED_PREFERENCES_NAME; - } - - @Singleton - @Provides - DaoSession provideDaoSession(DbHelper dbHelper) { - return new DaoMaster(dbHelper.getWritableDb()).newSession(); - } - - @Singleton - @Provides - Vulcan provideVulcan() { - return new Vulcan(); - } - - @Singleton - @Provides - RepositoryContract provideRepository(Repository repository) { - return repository; - } - - @Singleton - @Provides - SharedPrefContract provideSharedPref(SharedPrefRepository sharedPrefRepository) { - return sharedPrefRepository; - } - - @Singleton - @Provides - ResourcesContract provideAppResources(ResourcesRepository resourcesRepository) { - return resourcesRepository; - } - - - @Singleton - @Provides - DbContract provideDatabase(DbRepository dbRepository) { - return dbRepository; - } - - @Singleton - @Provides - SyncContract provideSync(SyncRepository syncRepository) { - return syncRepository; - } - - @Provides - FirebaseJobDispatcher provideDispatcher() { - return new FirebaseJobDispatcher(new GooglePlayDriver(application)); - } -} diff --git a/app/src/main/java/io/github/wulkanowy/di/modules/FragmentModule.java b/app/src/main/java/io/github/wulkanowy/di/modules/FragmentModule.java deleted file mode 100644 index 005b7aa12..000000000 --- a/app/src/main/java/io/github/wulkanowy/di/modules/FragmentModule.java +++ /dev/null @@ -1,103 +0,0 @@ -package io.github.wulkanowy.di.modules; - -import android.support.v4.app.Fragment; - -import dagger.Module; -import dagger.Provides; -import eu.davidea.flexibleadapter.FlexibleAdapter; -import io.github.wulkanowy.di.annotations.PerFragment; -import io.github.wulkanowy.ui.base.BasePagerAdapter; -import io.github.wulkanowy.ui.main.attendance.AttendanceContract; -import io.github.wulkanowy.ui.main.attendance.AttendanceHeaderItem; -import io.github.wulkanowy.ui.main.attendance.AttendancePresenter; -import io.github.wulkanowy.ui.main.attendance.AttendanceTabContract; -import io.github.wulkanowy.ui.main.attendance.AttendanceTabPresenter; -import io.github.wulkanowy.ui.main.exams.ExamsContract; -import io.github.wulkanowy.ui.main.exams.ExamsPresenter; -import io.github.wulkanowy.ui.main.exams.ExamsSubItem; -import io.github.wulkanowy.ui.main.exams.ExamsTabContract; -import io.github.wulkanowy.ui.main.exams.ExamsTabPresenter; -import io.github.wulkanowy.ui.main.grades.GradeHeaderItem; -import io.github.wulkanowy.ui.main.grades.GradesContract; -import io.github.wulkanowy.ui.main.grades.GradesPresenter; -import io.github.wulkanowy.ui.main.timetable.TimetableContract; -import io.github.wulkanowy.ui.main.timetable.TimetableHeaderItem; -import io.github.wulkanowy.ui.main.timetable.TimetablePresenter; -import io.github.wulkanowy.ui.main.timetable.TimetableTabContract; -import io.github.wulkanowy.ui.main.timetable.TimetableTabPresenter; - -@Module -public class FragmentModule { - - private final Fragment fragment; - - public FragmentModule(Fragment fragment) { - this.fragment = fragment; - } - - @PerFragment - @Provides - GradesContract.Presenter provideGradesPresenter(GradesPresenter gradesPresenter) { - return gradesPresenter; - } - - @PerFragment - @Provides - AttendanceContract.Presenter provideAttendancePresenter(AttendancePresenter attendancePresenter) { - return attendancePresenter; - } - - @PerFragment - @Provides - ExamsContract.Presenter provideDashboardPresenter(ExamsPresenter examsPresenter) { - return examsPresenter; - } - - @PerFragment - @Provides - AttendanceTabContract.Presenter provideAttendanceTabPresenter(AttendanceTabPresenter timetableTabPresenter) { - return timetableTabPresenter; - } - - @Provides - BasePagerAdapter provideBasePagerAdapter() { - return new BasePagerAdapter(fragment.getChildFragmentManager()); - } - - @Provides - FlexibleAdapter provideAttendanceTabAdapter() { - return new FlexibleAdapter<>(null); - } - - @Provides - FlexibleAdapter provideTimetableTabAdapter() { - return new FlexibleAdapter<>(null); - } - - @Provides - FlexibleAdapter provideGradesAdapter() { - return new FlexibleAdapter<>(null); - } - - @Provides - FlexibleAdapter provideExamAdapter() { - return new FlexibleAdapter<>(null); - } - - @PerFragment - @Provides - TimetableContract.Presenter provideTimetablePresenter(TimetablePresenter timetablePresenter) { - return timetablePresenter; - } - - @PerFragment - @Provides - TimetableTabContract.Presenter provideTimetableTabPresenter(TimetableTabPresenter timetableTabPresenter) { - return timetableTabPresenter; - } - - @Provides - ExamsTabContract.Presenter provideExamsTabPresenter(ExamsTabPresenter examsTabPresenter) { - return examsTabPresenter; - } -} diff --git a/app/src/main/java/io/github/wulkanowy/di/annotations/PerActivity.java b/app/src/main/java/io/github/wulkanowy/di/scopes/PerActivity.java similarity index 81% rename from app/src/main/java/io/github/wulkanowy/di/annotations/PerActivity.java rename to app/src/main/java/io/github/wulkanowy/di/scopes/PerActivity.java index f103994a5..c9fc8a5b2 100644 --- a/app/src/main/java/io/github/wulkanowy/di/annotations/PerActivity.java +++ b/app/src/main/java/io/github/wulkanowy/di/scopes/PerActivity.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.di.annotations; +package io.github.wulkanowy.di.scopes; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/app/src/main/java/io/github/wulkanowy/di/annotations/DatabaseInfo.java b/app/src/main/java/io/github/wulkanowy/di/scopes/PerChildFragment.java similarity index 51% rename from app/src/main/java/io/github/wulkanowy/di/annotations/DatabaseInfo.java rename to app/src/main/java/io/github/wulkanowy/di/scopes/PerChildFragment.java index fabcefbaa..67a9f8209 100644 --- a/app/src/main/java/io/github/wulkanowy/di/annotations/DatabaseInfo.java +++ b/app/src/main/java/io/github/wulkanowy/di/scopes/PerChildFragment.java @@ -1,11 +1,11 @@ -package io.github.wulkanowy.di.annotations; +package io.github.wulkanowy.di.scopes; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import javax.inject.Qualifier; +import javax.inject.Scope; -@Qualifier +@Scope @Retention(RetentionPolicy.RUNTIME) -public @interface DatabaseInfo { +public @interface PerChildFragment { } diff --git a/app/src/main/java/io/github/wulkanowy/di/annotations/PerFragment.java b/app/src/main/java/io/github/wulkanowy/di/scopes/PerFragment.java similarity index 81% rename from app/src/main/java/io/github/wulkanowy/di/annotations/PerFragment.java rename to app/src/main/java/io/github/wulkanowy/di/scopes/PerFragment.java index 98f364f76..a4d37c382 100644 --- a/app/src/main/java/io/github/wulkanowy/di/annotations/PerFragment.java +++ b/app/src/main/java/io/github/wulkanowy/di/scopes/PerFragment.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.di.annotations; +package io.github.wulkanowy.di.scopes; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java b/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java index ab79034f0..432bdc23a 100644 --- a/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java +++ b/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java @@ -20,8 +20,8 @@ import java.util.List; import javax.inject.Inject; +import dagger.android.AndroidInjection; import io.github.wulkanowy.R; -import io.github.wulkanowy.WulkanowyApp; import io.github.wulkanowy.data.RepositoryContract; import io.github.wulkanowy.data.db.dao.entities.Grade; import io.github.wulkanowy.data.sync.NotRegisteredUserException; @@ -60,7 +60,7 @@ public class SyncJob extends SimpleJobService { @Override public void onCreate() { super.onCreate(); - ((WulkanowyApp) getApplication()).getApplicationComponent().inject(this); + AndroidInjection.inject(this); } @Override diff --git a/app/src/main/java/io/github/wulkanowy/services/widgets/TimetableWidgetServices.java b/app/src/main/java/io/github/wulkanowy/services/widgets/TimetableWidgetServices.java index 728cc805d..f442542ef 100644 --- a/app/src/main/java/io/github/wulkanowy/services/widgets/TimetableWidgetServices.java +++ b/app/src/main/java/io/github/wulkanowy/services/widgets/TimetableWidgetServices.java @@ -3,12 +3,20 @@ package io.github.wulkanowy.services.widgets; import android.content.Intent; import android.widget.RemoteViewsService; +import javax.inject.Inject; + +import dagger.android.AndroidInjection; +import io.github.wulkanowy.data.RepositoryContract; import io.github.wulkanowy.ui.widgets.TimetableWidgetFactory; public class TimetableWidgetServices extends RemoteViewsService { + @Inject + RepositoryContract repository; + @Override public RemoteViewsFactory onGetViewFactory(Intent intent) { - return new TimetableWidgetFactory(getApplicationContext()); + AndroidInjection.inject(this); + return new TimetableWidgetFactory(getApplicationContext(), repository); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BaseActivity.java b/app/src/main/java/io/github/wulkanowy/ui/base/BaseActivity.java index c5c66df0c..50796816e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/BaseActivity.java +++ b/app/src/main/java/io/github/wulkanowy/ui/base/BaseActivity.java @@ -1,35 +1,51 @@ package io.github.wulkanowy.ui.base; import android.os.Bundle; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; +import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatDelegate; -import android.widget.Toast; +import android.view.View; +import butterknife.ButterKnife; import butterknife.Unbinder; +import dagger.android.support.DaggerAppCompatActivity; import io.github.wulkanowy.R; -import io.github.wulkanowy.WulkanowyApp; -import io.github.wulkanowy.di.component.ActivityComponent; -import io.github.wulkanowy.di.component.DaggerActivityComponent; -import io.github.wulkanowy.di.modules.ActivityModule; import io.github.wulkanowy.utils.NetworkUtils; -public abstract class BaseActivity extends AppCompatActivity implements BaseContract.View { - - private ActivityComponent activityComponent; +public abstract class BaseActivity extends DaggerAppCompatActivity implements BaseContract.View { private Unbinder unbinder; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); + } - activityComponent = DaggerActivityComponent.builder() - .activityModule(new ActivityModule(this)) - .applicationComponent(((WulkanowyApp) getApplication()).getApplicationComponent()) - .build(); + protected void injectViews() { + unbinder = ButterKnife.bind(this); + } + + @Override + public void showMessage(@NonNull String text) { + if (getMessageView() != null) { + Snackbar.make(getMessageView(), text, Snackbar.LENGTH_LONG).show(); + } + } + + @Override + public void showNoNetworkMessage() { + showMessage(getString(R.string.noInternet_text)); + } + + @Override + public boolean isNetworkConnected() { + return NetworkUtils.isOnline(getApplicationContext()); + } + + protected View getMessageView() { + return null; } @Override @@ -39,32 +55,4 @@ public abstract class BaseActivity extends AppCompatActivity implements BaseCont unbinder.unbind(); } } - - @Override - public void onError(int resId) { - onError(getString(resId)); - } - - @Override - public void onError(String message) { - Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); - } - - @Override - public void onNoNetworkError() { - onError(R.string.noInternet_text); - } - - @Override - public boolean isNetworkConnected() { - return NetworkUtils.isOnline(getApplicationContext()); - } - - public ActivityComponent getActivityComponent() { - return activityComponent; - } - - public void setButterKnife(Unbinder unbinder) { - this.unbinder = unbinder; - } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BaseContract.java b/app/src/main/java/io/github/wulkanowy/ui/base/BaseContract.java index 2a4dc5696..3bfa40d13 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/BaseContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/base/BaseContract.java @@ -1,27 +1,22 @@ package io.github.wulkanowy.ui.base; -import android.support.annotation.StringRes; - -import io.github.wulkanowy.di.annotations.PerActivity; +import android.support.annotation.NonNull; public interface BaseContract { interface View { - void onError(@StringRes int resId); + void showMessage(@NonNull String text); - void onError(String message); - - void onNoNetworkError(); + void showNoNetworkMessage(); boolean isNetworkConnected(); } - @PerActivity interface Presenter { - void onStart(V view); + void attachView(@NonNull V view); - void onDestroy(); + void detachView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.java b/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.java index efb9d61a9..e2a5a9e02 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.java @@ -1,56 +1,20 @@ package io.github.wulkanowy.ui.base; -import android.content.Context; -import android.os.Bundle; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; +import android.support.annotation.StringRes; import android.view.View; +import butterknife.ButterKnife; import butterknife.Unbinder; -import io.github.wulkanowy.R; -import io.github.wulkanowy.WulkanowyApp; -import io.github.wulkanowy.di.component.DaggerFragmentComponent; -import io.github.wulkanowy.di.component.FragmentComponent; -import io.github.wulkanowy.di.modules.FragmentModule; +import dagger.android.support.DaggerFragment; +import io.github.wulkanowy.utils.NetworkUtils; -public abstract class BaseFragment extends Fragment implements BaseContract.View { - - private BaseActivity activity; +public abstract class BaseFragment extends DaggerFragment implements BaseContract.View { private Unbinder unbinder; - private FragmentComponent fragmentComponent; - - @Override - public void onAttach(Context context) { - super.onAttach(context); - if (context instanceof BaseActivity) { - activity = (BaseActivity) context; - } - - fragmentComponent = DaggerFragmentComponent.builder() - .fragmentModule(new FragmentModule(this)) - .applicationComponent(((WulkanowyApp) activity.getApplication()).getApplicationComponent()) - .build(); - } - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setHasOptionsMenu(false); - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - setUpOnViewCreated(view); - } - - @Override - public void onDetach() { - activity = null; - super.onDetach(); + protected void injectViews(@NonNull View view) { + unbinder = ButterKnife.bind(this, view); } @Override @@ -61,44 +25,32 @@ public abstract class BaseFragment extends Fragment implements BaseContract.View super.onDestroyView(); } - @Override - public void onError(int resId) { - onError(getString(resId)); - } - - @Override - public void onError(String message) { - if (activity != null) { - activity.onError(message); + public void setTitle(String title) { + if (getActivity() != null) { + getActivity().setTitle(title); } } @Override - public void onNoNetworkError() { - onError(R.string.noInternet_text); + public void showMessage(@NonNull String text) { + if (getActivity() != null) { + ((BaseActivity) getActivity()).showMessage(text); + } + } + + public void showMessage(@StringRes int stringId) { + showMessage(getString(stringId)); + } + + @Override + public void showNoNetworkMessage() { + if (getActivity() != null) { + ((BaseActivity) getActivity()).showNoNetworkMessage(); + } } @Override public boolean isNetworkConnected() { - return activity != null && activity.isNetworkConnected(); - } - - public void setButterKnife(Unbinder unbinder) { - this.unbinder = unbinder; - } - - public void setTitle(String title) { - if (activity != null) { - activity.setTitle(title); - } - } - - public FragmentComponent getFragmentComponent() { - return fragmentComponent; - } - - - protected void setUpOnViewCreated(View fragmentView) { - // do something on view created + return NetworkUtils.isOnline(getContext()); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BasePresenter.java b/app/src/main/java/io/github/wulkanowy/ui/base/BasePresenter.java index 611b7a29e..8f9b8af0b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/BasePresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/base/BasePresenter.java @@ -1,5 +1,7 @@ package io.github.wulkanowy.ui.base; +import android.support.annotation.NonNull; + import javax.inject.Inject; import io.github.wulkanowy.data.RepositoryContract; @@ -16,12 +18,12 @@ public class BasePresenter implements BaseContract. } @Override - public void onStart(V view) { + public void attachView(@NonNull V view) { this.view = view; } @Override - public void onDestroy() { + public void detachView() { view = null; } diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.java b/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.java index 9d6e8b128..37f3e03ea 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.java +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.java @@ -5,7 +5,7 @@ import android.animation.AnimatorListenerAdapter; import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.support.design.widget.Snackbar; +import android.support.annotation.NonNull; import android.support.design.widget.TextInputLayout; import android.support.v7.app.ActionBar; import android.view.View; @@ -18,7 +18,6 @@ import android.widget.TextView; import javax.inject.Inject; import butterknife.BindView; -import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.OnEditorAction; import io.github.wulkanowy.R; @@ -64,14 +63,10 @@ public class LoginActivity extends BaseActivity implements LoginContract.View { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); + injectViews(); - setButterKnife(ButterKnife.bind(this)); - getActivityComponent().inject(this); - - presenter.onStart(this); - + presenter.attachView(this); setUpOnCreate(); - } protected void setUpOnCreate() { @@ -165,12 +160,6 @@ public class LoginActivity extends BaseActivity implements LoginContract.View { KeyboardUtils.hideSoftInput(this); } - @Override - public void onError(String message) { - Snackbar.make(findViewById(R.id.login_activity_container), message, - Snackbar.LENGTH_LONG).show(); - } - @Override public void setStepOneLoginProgress() { onLoginProgressUpdate("1", getString(R.string.step_login)); @@ -222,13 +211,19 @@ public class LoginActivity extends BaseActivity implements LoginContract.View { } } + @NonNull @Override - public void onDestroy() { - super.onDestroy(); - presenter.onDestroy(); + protected View getMessageView() { + return findViewById(R.id.login_activity_container); } private void onLoginProgressUpdate(String step, String message) { loginProgressText.setText(String.format("%1$s/2 - %2$s...", step, message)); } + + @Override + public void onDestroy() { + presenter.detachView(); + super.onDestroy(); + } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginContract.java b/app/src/main/java/io/github/wulkanowy/ui/login/LoginContract.java index 570e1b265..10f27f030 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginContract.java @@ -1,7 +1,5 @@ package io.github.wulkanowy.ui.login; -import io.github.wulkanowy.data.RepositoryContract; -import io.github.wulkanowy.di.annotations.PerActivity; import io.github.wulkanowy.ui.base.BaseContract; public interface LoginContract { @@ -37,7 +35,6 @@ public interface LoginContract { } - @PerActivity interface Presenter extends BaseContract.Presenter { void attemptLogin(String email, String password, String symbol); @@ -51,7 +48,5 @@ public interface LoginContract { void onEndAsync(boolean success, Exception exception); void onCanceledAsync(); - - RepositoryContract getRepository(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginModule.java b/app/src/main/java/io/github/wulkanowy/ui/login/LoginModule.java new file mode 100644 index 000000000..0cb26c496 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginModule.java @@ -0,0 +1,13 @@ +package io.github.wulkanowy.ui.login; + +import dagger.Binds; +import dagger.Module; +import io.github.wulkanowy.di.scopes.PerActivity; + +@Module +public abstract class LoginModule { + + @PerActivity + @Binds + abstract LoginContract.Presenter provideLoginPresenter(LoginPresenter loginPresenter); +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java index e5b37a6ee..fb63e6af2 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java @@ -47,7 +47,7 @@ public class LoginPresenter extends BasePresenter loginAsync.execute(); } else { - getView().onNoNetworkError(); + getView().showNoNetworkMessage(); } getView().hideSoftInput(); @@ -96,7 +96,7 @@ public class LoginPresenter extends BasePresenter getView().showSoftInput(); } else { FabricUtils.logRegister(false, symbol); - getView().onError(getRepository().getResRepo().getErrorLoginMessage(exception)); + getView().showMessage(getRepository().getResRepo().getErrorLoginMessage(exception)); } getView().showActionBar(true); @@ -160,11 +160,11 @@ public class LoginPresenter extends BasePresenter } @Override - public void onDestroy() { + public void detachView() { if (loginAsync != null) { loginAsync.cancel(true); loginAsync = null; } - super.onDestroy(); + super.detachView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java b/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java index 6b7d07cf3..f00f57c26 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java @@ -4,6 +4,7 @@ import android.content.Context; import android.content.Intent; import android.graphics.Color; import android.os.Bundle; +import android.support.annotation.NonNull; import android.support.v7.app.ActionBar; import android.support.v7.widget.Toolbar; import android.view.View; @@ -13,9 +14,9 @@ import com.aurelhubert.ahbottomnavigation.AHBottomNavigationItem; import com.aurelhubert.ahbottomnavigation.AHBottomNavigationViewPager; import javax.inject.Inject; +import javax.inject.Named; import butterknife.BindView; -import butterknife.ButterKnife; import io.github.wulkanowy.R; import io.github.wulkanowy.services.jobs.SyncJob; import io.github.wulkanowy.ui.base.BaseActivity; @@ -40,6 +41,7 @@ public class MainActivity extends BaseActivity implements MainContract.View, @BindView(R.id.main_activity_progress_bar) View progressBar; + @Named("Main") @Inject BasePagerAdapter pagerAdapter; @@ -55,11 +57,9 @@ public class MainActivity extends BaseActivity implements MainContract.View, super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); setSupportActionBar((Toolbar) findViewById(R.id.toolbar)); + injectViews(); - getActivityComponent().inject(this); - setButterKnife(ButterKnife.bind(this)); - - presenter.onStart(this, getIntent().getIntExtra(EXTRA_CARD_ID_KEY, -1)); + presenter.attachView(this, getIntent().getIntExtra(EXTRA_CARD_ID_KEY, -1)); } @Override @@ -146,9 +146,15 @@ public class MainActivity extends BaseActivity implements MainContract.View, SyncJob.start(getApplicationContext(), interval, useOnlyWifi); } + @NonNull + @Override + protected View getMessageView() { + return findViewById(R.id.main_activity_view_pager); + } + @Override protected void onDestroy() { + presenter.detachView(); super.onDestroy(); - presenter.onDestroy(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/MainContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/MainContract.java index cc3266548..cb4e29e46 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/MainContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/MainContract.java @@ -1,6 +1,7 @@ package io.github.wulkanowy.ui.main; -import io.github.wulkanowy.di.annotations.PerActivity; +import android.support.annotation.NonNull; + import io.github.wulkanowy.ui.base.BaseContract; public interface MainContract { @@ -22,10 +23,9 @@ public interface MainContract { void startSyncService(int interval, boolean useOnlyWifi); } - @PerActivity interface Presenter extends BaseContract.Presenter { - void onStart(View view, int tabPositionIntent); + void attachView(@NonNull View view, int initTabId); void onTabSelected(int position, boolean wasSelected); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/MainModule.java b/app/src/main/java/io/github/wulkanowy/ui/main/MainModule.java new file mode 100644 index 000000000..ff3fed67a --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/MainModule.java @@ -0,0 +1,50 @@ +package io.github.wulkanowy.ui.main; + +import javax.inject.Named; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; +import dagger.android.ContributesAndroidInjector; +import io.github.wulkanowy.di.scopes.PerActivity; +import io.github.wulkanowy.di.scopes.PerFragment; +import io.github.wulkanowy.ui.base.BasePagerAdapter; +import io.github.wulkanowy.ui.main.attendance.AttendanceFragment; +import io.github.wulkanowy.ui.main.attendance.AttendanceModule; +import io.github.wulkanowy.ui.main.exams.ExamsFragment; +import io.github.wulkanowy.ui.main.exams.ExamsModule; +import io.github.wulkanowy.ui.main.grades.GradesFragment; +import io.github.wulkanowy.ui.main.grades.GradesModule; +import io.github.wulkanowy.ui.main.timetable.TimetableFragment; +import io.github.wulkanowy.ui.main.timetable.TimetableModule; + +@Module +public abstract class MainModule { + + @PerActivity + @Binds + abstract MainContract.Presenter provideMainPresenter(MainPresenter mainPresenter); + + @Named("Main") + @PerActivity + @Provides + static BasePagerAdapter provideAdapter(MainActivity activity) { + return new BasePagerAdapter(activity.getSupportFragmentManager()); + } + + @PerFragment + @ContributesAndroidInjector(modules = GradesModule.class) + abstract GradesFragment bindsGradesFragment(); + + @PerFragment + @ContributesAndroidInjector(modules = TimetableModule.class) + abstract TimetableFragment bindTimetableFragment(); + + @PerFragment + @ContributesAndroidInjector(modules = ExamsModule.class) + abstract ExamsFragment bindExamsFragment(); + + @PerFragment + @ContributesAndroidInjector(modules = AttendanceModule.class) + abstract AttendanceFragment bindAttendanceFramgnet(); +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/MainPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/MainPresenter.java index ba5e41d8e..c6741c3ee 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/MainPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/MainPresenter.java @@ -1,6 +1,8 @@ package io.github.wulkanowy.ui.main; +import android.support.annotation.NonNull; + import javax.inject.Inject; import io.github.wulkanowy.data.RepositoryContract; @@ -17,15 +19,15 @@ public class MainPresenter extends BasePresenter } @Override - public void onStart(MainContract.View view, int tabPositionIntent) { - super.onStart(view); + public void attachView(@NonNull MainContract.View view, int initTabId) { + super.attachView(view); getView().showProgressBar(true); getView().hideActionBar(); int tabPosition; - if (tabPositionIntent != -1) { - tabPosition = tabPositionIntent; + if (initTabId != -1) { + tabPosition = initTabId; } else { tabPosition = getRepository().getSharedRepo().getStartupTab(); } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceContract.java index daee63d28..1ad66787e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceContract.java @@ -1,6 +1,7 @@ package io.github.wulkanowy.ui.main.attendance; -import io.github.wulkanowy.di.annotations.PerActivity; +import android.support.annotation.NonNull; + import io.github.wulkanowy.ui.base.BaseContract; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; @@ -21,12 +22,11 @@ public interface AttendanceContract { void setThemeForTab(int position); } - @PerActivity interface Presenter extends BaseContract.Presenter { void onFragmentActivated(boolean isVisible); - void onStart(View view, OnFragmentIsReadyListener listener); + void attachView(@NonNull View view, OnFragmentIsReadyListener listener); void setRestoredPosition(int position); } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceFragment.java index e26c9fc7b..732806db9 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceFragment.java @@ -3,7 +3,6 @@ package io.github.wulkanowy.ui.main.attendance; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.design.widget.Snackbar; import android.support.design.widget.TabLayout; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; @@ -11,14 +10,14 @@ import android.view.View; import android.view.ViewGroup; import javax.inject.Inject; +import javax.inject.Named; import butterknife.BindView; -import butterknife.ButterKnife; import io.github.wulkanowy.R; -import io.github.wulkanowy.di.component.FragmentComponent; import io.github.wulkanowy.ui.base.BaseFragment; import io.github.wulkanowy.ui.base.BasePagerAdapter; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; +import io.github.wulkanowy.ui.main.attendance.tab.AttendanceTabFragment; public class AttendanceFragment extends BaseFragment implements AttendanceContract.View { @@ -31,6 +30,7 @@ public class AttendanceFragment extends BaseFragment implements AttendanceContra TabLayout tabLayout; @Inject + @Named("Attendance") BasePagerAdapter pagerAdapter; @Inject @@ -41,18 +41,13 @@ public class AttendanceFragment extends BaseFragment implements AttendanceContra public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_attendance, container, false); + injectViews(view); - FragmentComponent component = getFragmentComponent(); - if (component != null) { - component.inject(this); - setButterKnife(ButterKnife.bind(this, view)); - presenter.onStart(this, (OnFragmentIsReadyListener) getActivity()); + presenter.attachView(this, (OnFragmentIsReadyListener) getActivity()); - if (savedInstanceState != null) { - presenter.setRestoredPosition(savedInstanceState.getInt(CURRENT_ITEM_KEY)); - } + if (savedInstanceState != null) { + presenter.setRestoredPosition(savedInstanceState.getInt(CURRENT_ITEM_KEY)); } - return view; } @@ -93,14 +88,6 @@ public class AttendanceFragment extends BaseFragment implements AttendanceContra setTitle(getString(R.string.attendance_text)); } - @Override - public void onError(String message) { - if (getActivity() != null) { - Snackbar.make(getActivity().findViewById(R.id.main_activity_view_pager), - message, Snackbar.LENGTH_LONG).show(); - } - } - @Override public void onSaveInstanceState(Bundle outState) { outState.putInt(CURRENT_ITEM_KEY, viewPager.getCurrentItem()); @@ -109,7 +96,7 @@ public class AttendanceFragment extends BaseFragment implements AttendanceContra @Override public void onDestroyView() { - presenter.onDestroy(); + presenter.detachView(); super.onDestroyView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceModule.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceModule.java new file mode 100644 index 000000000..8679cf100 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceModule.java @@ -0,0 +1,32 @@ +package io.github.wulkanowy.ui.main.attendance; + +import javax.inject.Named; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; +import dagger.android.ContributesAndroidInjector; +import io.github.wulkanowy.di.scopes.PerChildFragment; +import io.github.wulkanowy.di.scopes.PerFragment; +import io.github.wulkanowy.ui.base.BasePagerAdapter; +import io.github.wulkanowy.ui.main.attendance.tab.AttendanceTabFragment; +import io.github.wulkanowy.ui.main.attendance.tab.AttendanceTabModule; + +@Module +public abstract class AttendanceModule { + + @PerFragment + @Binds + abstract AttendanceContract.Presenter provideAttendancePresenter(AttendancePresenter attendancePresenter); + + @PerFragment + @Named("Attendance") + @Provides + static BasePagerAdapter providePagerAdapter(AttendanceFragment fragment) { + return new BasePagerAdapter(fragment.getChildFragmentManager()); + } + + @PerChildFragment + @ContributesAndroidInjector(modules = AttendanceTabModule.class) + abstract AttendanceTabFragment bindAttendanceTabFragment(); +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendancePresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendancePresenter.java index 55541ed26..9cfb13848 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendancePresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendancePresenter.java @@ -1,5 +1,7 @@ package io.github.wulkanowy.ui.main.attendance; +import android.support.annotation.NonNull; + import java.util.ArrayList; import java.util.List; @@ -31,8 +33,8 @@ public class AttendancePresenter extends BasePresenter } @Override - public void onStart(AttendanceContract.View view, OnFragmentIsReadyListener listener) { - super.onStart(view); + public void attachView(@NonNull AttendanceContract.View view, OnFragmentIsReadyListener listener) { + super.attachView(view); this.listener = listener; if (getView().isMenuVisible()) { @@ -64,7 +66,7 @@ public class AttendancePresenter extends BasePresenter } @Override - public void onDoInBackgroundLoading() throws Exception { + public void onDoInBackgroundLoading() { for (String date : dates) { getView().setTabDataToAdapter(date); } @@ -92,14 +94,13 @@ public class AttendancePresenter extends BasePresenter } @Override - public void onDestroy() { + public void detachView() { isFirstSight = false; if (loadingTask != null) { loadingTask.cancel(true); loadingTask = null; } - - super.onDestroy(); + super.detachView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceHeaderItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceHeaderItem.java similarity index 99% rename from app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceHeaderItem.java rename to app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceHeaderItem.java index b7e6aecd9..1c55f40c0 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceHeaderItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceHeaderItem.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.ui.main.attendance; +package io.github.wulkanowy.ui.main.attendance.tab; import android.content.Context; import android.content.res.TypedArray; diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceSubItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceSubItem.java similarity index 96% rename from app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceSubItem.java rename to app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceSubItem.java index 440d878e7..6b6246d25 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceSubItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceSubItem.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.ui.main.attendance; +package io.github.wulkanowy.ui.main.attendance.tab; import android.content.Context; import android.support.v4.app.DialogFragment; @@ -20,6 +20,7 @@ import eu.davidea.flexibleadapter.items.IFlexible; import eu.davidea.viewholders.FlexibleViewHolder; import io.github.wulkanowy.R; import io.github.wulkanowy.data.db.dao.entities.AttendanceLesson; +import io.github.wulkanowy.ui.main.attendance.AttendanceDialogFragment; class AttendanceSubItem extends AbstractSectionableItem { diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabContract.java similarity index 92% rename from app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabContract.java rename to app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabContract.java index dcb16bf88..d7c459042 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabContract.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.ui.main.attendance; +package io.github.wulkanowy.ui.main.attendance.tab; import java.util.List; diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabFragment.java similarity index 76% rename from app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabFragment.java rename to app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabFragment.java index e5e65bb9d..7b5ad1cec 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabFragment.java @@ -1,9 +1,8 @@ -package io.github.wulkanowy.ui.main.attendance; +package io.github.wulkanowy.ui.main.attendance.tab; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.design.widget.Snackbar; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; @@ -15,11 +14,9 @@ import java.util.List; import javax.inject.Inject; import butterknife.BindView; -import butterknife.ButterKnife; import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager; import io.github.wulkanowy.R; -import io.github.wulkanowy.di.component.FragmentComponent; import io.github.wulkanowy.ui.base.BaseFragment; public class AttendanceTabFragment extends BaseFragment implements AttendanceTabContract.View, @@ -61,34 +58,28 @@ public class AttendanceTabFragment extends BaseFragment implements AttendanceTab @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_attendance_tab, container, false); + injectViews(view); - FragmentComponent component = getFragmentComponent(); - if (component != null) { - component.inject(this); - setButterKnife(ButterKnife.bind(this, view)); - - if (getArguments() != null) { - presenter.setArgumentDate(getArguments().getString(ARGUMENT_KEY)); - } - - presenter.onStart(this); - presenter.onFragmentActivated(isFragmentVisible); + if (getArguments() != null) { + presenter.setArgumentDate(getArguments().getString(ARGUMENT_KEY)); } + + presenter.attachView(this); + presenter.onFragmentActivated(isFragmentVisible); return view; } @Override - protected void setUpOnViewCreated(View fragmentView) { + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { adapter.setAutoCollapseOnExpand(true); adapter.setAutoScrollOnExpand(true); adapter.expandItemsAtStartUp(); - recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(fragmentView.getContext())); + recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(view.getContext())); recyclerView.setAdapter(adapter); refreshLayout.setColorSchemeResources(android.R.color.black); refreshLayout.setOnRefreshListener(this); - } @Override @@ -112,7 +103,7 @@ public class AttendanceTabFragment extends BaseFragment implements AttendanceTab @Override public void onRefreshSuccess() { - onError(R.string.sync_completed); + showMessage(R.string.sync_completed); } @Override @@ -130,17 +121,9 @@ public class AttendanceTabFragment extends BaseFragment implements AttendanceTab noItemView.setVisibility(show ? View.VISIBLE : View.INVISIBLE); } - @Override - public void onError(String message) { - if (getActivity() != null) { - Snackbar.make(getActivity().findViewById(R.id.main_activity_view_pager), - message, Snackbar.LENGTH_LONG).show(); - } - } - @Override public void onDestroyView() { - presenter.onDestroy(); + presenter.detachView(); super.onDestroyView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabModule.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabModule.java new file mode 100644 index 000000000..01bb9aa40 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabModule.java @@ -0,0 +1,21 @@ +package io.github.wulkanowy.ui.main.attendance.tab; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; +import eu.davidea.flexibleadapter.FlexibleAdapter; +import io.github.wulkanowy.di.scopes.PerChildFragment; + +@Module +public abstract class AttendanceTabModule { + + @PerChildFragment + @Binds + abstract AttendanceTabContract.Presenter provideAttendanceTabPresenter(AttendanceTabPresenter attendanceTabPresenter); + + @PerChildFragment + @Provides + static FlexibleAdapter provideAdapter() { + return new FlexibleAdapter<>(null); + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabPresenter.java similarity index 92% rename from app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabPresenter.java rename to app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabPresenter.java index 72cab5d33..787b6eb9d 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/AttendanceTabPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabPresenter.java @@ -1,4 +1,6 @@ -package io.github.wulkanowy.ui.main.attendance; +package io.github.wulkanowy.ui.main.attendance.tab; + +import android.support.annotation.NonNull; import java.util.ArrayList; import java.util.List; @@ -34,8 +36,9 @@ public class AttendanceTabPresenter extends BasePresenter { - void onStart(View view, OnFragmentIsReadyListener listener); + void attachView(@NonNull View view, OnFragmentIsReadyListener listener); void onFragmentActivated(boolean isVisible); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsFragment.java index cab3b902e..503257982 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsFragment.java @@ -10,14 +10,15 @@ import android.view.View; import android.view.ViewGroup; import javax.inject.Inject; +import javax.inject.Named; import butterknife.BindView; import butterknife.ButterKnife; import io.github.wulkanowy.R; -import io.github.wulkanowy.di.component.FragmentComponent; import io.github.wulkanowy.ui.base.BaseFragment; import io.github.wulkanowy.ui.base.BasePagerAdapter; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; +import io.github.wulkanowy.ui.main.exams.tab.ExamsTabFragment; public class ExamsFragment extends BaseFragment implements ExamsContract.View { @@ -30,6 +31,7 @@ public class ExamsFragment extends BaseFragment implements ExamsContract.View { TabLayout tabLayout; @Inject + @Named("Exams") BasePagerAdapter pagerAdapter; @Inject @@ -39,16 +41,12 @@ public class ExamsFragment extends BaseFragment implements ExamsContract.View { public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_exams, container, false); + injectViews(view); - FragmentComponent component = getFragmentComponent(); - if (component != null) { - component.inject(this); - setButterKnife(ButterKnife.bind(this, view)); - presenter.onStart(this, (OnFragmentIsReadyListener) getActivity()); + presenter.attachView(this, (OnFragmentIsReadyListener) getActivity()); - if (savedInstanceState != null) { - presenter.setRestoredPosition(savedInstanceState.getInt(CURRENT_ITEM_KEY)); - } + if (savedInstanceState != null) { + presenter.setRestoredPosition(savedInstanceState.getInt(CURRENT_ITEM_KEY)); } return view; } @@ -61,14 +59,6 @@ public class ExamsFragment extends BaseFragment implements ExamsContract.View { } } - @Override - public void onError(String message) { - if (getActivity() != null) { - Snackbar.make(getActivity().findViewById(R.id.main_activity_view_pager), - message, Snackbar.LENGTH_LONG).show(); - } - } - @Override public void setActivityTitle() { setTitle(getString(R.string.exams_text)); @@ -107,6 +97,6 @@ public class ExamsFragment extends BaseFragment implements ExamsContract.View { @Override public void onDestroyView() { super.onDestroyView(); - presenter.onDestroy(); + presenter.detachView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsModule.java b/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsModule.java new file mode 100644 index 000000000..8d56cf234 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsModule.java @@ -0,0 +1,32 @@ +package io.github.wulkanowy.ui.main.exams; + +import javax.inject.Named; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; +import dagger.android.ContributesAndroidInjector; +import io.github.wulkanowy.di.scopes.PerChildFragment; +import io.github.wulkanowy.di.scopes.PerFragment; +import io.github.wulkanowy.ui.base.BasePagerAdapter; +import io.github.wulkanowy.ui.main.exams.tab.ExamsTabFragment; +import io.github.wulkanowy.ui.main.exams.tab.ExamsTabModule; + +@Module +public abstract class ExamsModule { + + @PerFragment + @Binds + abstract ExamsContract.Presenter provideExamsPresneter(ExamsPresenter examsPresenter); + + @Named("Exams") + @PerFragment + @Provides + static BasePagerAdapter providePagerAdapter(ExamsFragment fragment) { + return new BasePagerAdapter(fragment.getChildFragmentManager()); + } + + @PerChildFragment + @ContributesAndroidInjector(modules = ExamsTabModule.class) + abstract ExamsTabFragment bindExamsTabFragment(); +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsPresenter.java index 5f6cd4dc9..a5bd1055e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsPresenter.java @@ -1,5 +1,7 @@ package io.github.wulkanowy.ui.main.exams; +import android.support.annotation.NonNull; + import java.util.ArrayList; import java.util.List; @@ -31,8 +33,8 @@ public class ExamsPresenter extends BasePresenter } @Override - public void onStart(ExamsContract.View view, OnFragmentIsReadyListener listener) { - super.onStart(view); + public void attachView(@NonNull ExamsContract.View view, OnFragmentIsReadyListener listener) { + super.attachView(view); this.listener = listener; if (getView().isMenuVisible()) { @@ -69,7 +71,7 @@ public class ExamsPresenter extends BasePresenter } @Override - public void onDoInBackgroundLoading() throws Exception { + public void onDoInBackgroundLoading() { for (String date : dates) { getView().setTabDataToAdapter(date); } @@ -91,13 +93,13 @@ public class ExamsPresenter extends BasePresenter } @Override - public void onDestroy() { + public void detachView() { isFirstSight = false; if (loadingTask != null) { loadingTask.cancel(true); loadingTask = null; } - super.onDestroy(); + super.detachView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsHeaderItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsHeaderItem.java similarity index 96% rename from app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsHeaderItem.java rename to app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsHeaderItem.java index 86070515b..e1d719904 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsHeaderItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsHeaderItem.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.ui.main.exams; +package io.github.wulkanowy.ui.main.exams.tab; import android.view.View; import android.widget.TextView; @@ -22,7 +22,7 @@ public class ExamsHeaderItem extends AbstractHeaderItem { diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsTabContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabContract.java similarity index 83% rename from app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsTabContract.java rename to app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabContract.java index ec59628a8..4e0785bb2 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsTabContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabContract.java @@ -1,8 +1,7 @@ -package io.github.wulkanowy.ui.main.exams; +package io.github.wulkanowy.ui.main.exams.tab; import java.util.List; -import io.github.wulkanowy.di.annotations.PerFragment; import io.github.wulkanowy.ui.base.BaseContract; public interface ExamsTabContract { @@ -20,7 +19,6 @@ public interface ExamsTabContract { void updateAdapterList(List headerItems); } - @PerFragment interface Presenter extends BaseContract.Presenter { void onFragmentActivated(boolean isSelected); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsTabFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabFragment.java similarity index 74% rename from app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsTabFragment.java rename to app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabFragment.java index d41e34d2b..1b6f361a4 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsTabFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabFragment.java @@ -1,8 +1,7 @@ -package io.github.wulkanowy.ui.main.exams; +package io.github.wulkanowy.ui.main.exams.tab; import android.os.Bundle; import android.support.annotation.Nullable; -import android.support.design.widget.Snackbar; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; @@ -14,11 +13,9 @@ import java.util.List; import javax.inject.Inject; import butterknife.BindView; -import butterknife.ButterKnife; import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager; import io.github.wulkanowy.R; -import io.github.wulkanowy.di.component.FragmentComponent; import io.github.wulkanowy.ui.base.BaseFragment; public class ExamsTabFragment extends BaseFragment implements ExamsTabContract.View, @@ -60,26 +57,21 @@ public class ExamsTabFragment extends BaseFragment implements ExamsTabContract.V @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_exams_tab, container, false); + injectViews(view); - FragmentComponent component = getFragmentComponent(); - if (component != null) { - component.inject(this); - setButterKnife(ButterKnife.bind(this, view)); - - if (getArguments() != null) { - presenter.setArgumentDate(getArguments().getString(ARGUMENT_KEY)); - } - presenter.onStart(this); - presenter.onFragmentActivated(isFragmentVisible); + if (getArguments() != null) { + presenter.setArgumentDate(getArguments().getString(ARGUMENT_KEY)); } + presenter.attachView(this); + presenter.onFragmentActivated(isFragmentVisible); return view; } @Override - protected void setUpOnViewCreated(View fragmentView) { + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { adapter.setDisplayHeadersAtStartUp(true); - recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(fragmentView.getContext())); + recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(view.getContext())); recyclerView.setAdapter(adapter); refreshLayout.setColorSchemeResources(android.R.color.black); @@ -107,7 +99,7 @@ public class ExamsTabFragment extends BaseFragment implements ExamsTabContract.V @Override public void onRefreshSuccess() { - onError(R.string.sync_completed); + showMessage(R.string.sync_completed); } @Override @@ -125,17 +117,10 @@ public class ExamsTabFragment extends BaseFragment implements ExamsTabContract.V progressBar.setVisibility(show ? View.VISIBLE : View.INVISIBLE); } - @Override - public void onError(String message) { - if (getActivity() != null) { - Snackbar.make(getActivity().findViewById(R.id.main_activity_view_pager), - message, Snackbar.LENGTH_LONG).show(); - } - } @Override public void onDestroyView() { - presenter.onDestroy(); + presenter.detachView(); super.onDestroyView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabModule.java b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabModule.java new file mode 100644 index 000000000..fc9a7595e --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabModule.java @@ -0,0 +1,21 @@ +package io.github.wulkanowy.ui.main.exams.tab; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; +import eu.davidea.flexibleadapter.FlexibleAdapter; +import io.github.wulkanowy.di.scopes.PerChildFragment; + +@Module +public abstract class ExamsTabModule { + + @PerChildFragment + @Binds + abstract ExamsTabContract.Presenter provideExamsTabPresenter(ExamsTabPresenter examsTabPresenter); + + @PerChildFragment + @Provides + static FlexibleAdapter provideAdapter() { + return new FlexibleAdapter<>(null); + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsTabPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabPresenter.java similarity index 90% rename from app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsTabPresenter.java rename to app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabPresenter.java index 5925b3577..062c0fd83 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsTabPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabPresenter.java @@ -1,4 +1,6 @@ -package io.github.wulkanowy.ui.main.exams; +package io.github.wulkanowy.ui.main.exams.tab; + +import android.support.annotation.NonNull; import java.util.ArrayList; import java.util.List; @@ -29,13 +31,13 @@ public class ExamsTabPresenter extends BasePresenter private boolean isFirstSight = false; @Inject - public ExamsTabPresenter(RepositoryContract repository) { + ExamsTabPresenter(RepositoryContract repository) { super(repository); } @Override - public void onStart(ExamsTabContract.View view) { - super.onStart(view); + public void attachView(@NonNull ExamsTabContract.View view) { + super.attachView(view); getView().showProgressBar(true); getView().showNoItem(false); } @@ -65,7 +67,7 @@ public class ExamsTabPresenter extends BasePresenter refreshTask.setOnRefreshListener(this); refreshTask.execute(); } else { - getView().onNoNetworkError(); + getView().showNoNetworkMessage(); getView().hideRefreshingBar(); } } @@ -91,7 +93,7 @@ public class ExamsTabPresenter extends BasePresenter getView().onRefreshSuccess(); } else { - getView().onError(getRepository().getResRepo().getErrorLoginMessage(exception)); + getView().showMessage(getRepository().getResRepo().getErrorLoginMessage(exception)); } getView().hideRefreshingBar(); @@ -157,9 +159,9 @@ public class ExamsTabPresenter extends BasePresenter } @Override - public void onDestroy() { + public void detachView() { isFirstSight = false; cancelAsyncTasks(); - super.onDestroy(); + super.detachView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesContract.java index 07ca0d737..5583f98c9 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesContract.java @@ -1,10 +1,10 @@ package io.github.wulkanowy.ui.main.grades; +import android.support.annotation.NonNull; import android.support.v4.widget.SwipeRefreshLayout; import java.util.List; -import io.github.wulkanowy.di.annotations.PerActivity; import io.github.wulkanowy.ui.base.BaseContract; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; @@ -30,14 +30,13 @@ public interface GradesContract { } - @PerActivity interface Presenter extends BaseContract.Presenter { void onFragmentVisible(boolean isVisible); void onRefresh(); - void onStart(View view, OnFragmentIsReadyListener listener); + void attachView(@NonNull View view, OnFragmentIsReadyListener listener); void onSemesterChange(int which); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java index 5a31736b3..09c0a1bbc 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java @@ -4,7 +4,6 @@ import android.content.DialogInterface; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.design.widget.Snackbar; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.AlertDialog; import android.support.v7.widget.RecyclerView; @@ -20,11 +19,9 @@ import java.util.List; import javax.inject.Inject; import butterknife.BindView; -import butterknife.ButterKnife; import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager; import io.github.wulkanowy.R; -import io.github.wulkanowy.di.component.FragmentComponent; import io.github.wulkanowy.ui.base.BaseFragment; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; @@ -55,14 +52,9 @@ public class GradesFragment extends BaseFragment implements GradesContract.View @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_grades, container, false); + injectViews(view); - FragmentComponent component = getFragmentComponent(); - if (component != null) { - component.inject(this); - setButterKnife(ButterKnife.bind(this, view)); - presenter.onStart(this, (OnFragmentIsReadyListener) getActivity()); - } - + presenter.attachView(this, (OnFragmentIsReadyListener) getActivity()); return view; } @@ -102,14 +94,14 @@ public class GradesFragment extends BaseFragment implements GradesContract.View } @Override - protected void setUpOnViewCreated(View fragmentView) { + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { noItemView.setVisibility(View.GONE); adapter.setAutoCollapseOnExpand(true); adapter.setAutoScrollOnExpand(true); adapter.expandItemsAtStartUp(); - recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(fragmentView.getContext())); + recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(view.getContext())); recyclerView.setAdapter(adapter); refreshLayout.setColorSchemeResources(android.R.color.black); @@ -155,25 +147,17 @@ public class GradesFragment extends BaseFragment implements GradesContract.View @Override public void onRefreshSuccessNoGrade() { - onError(R.string.snackbar_no_grades); + showMessage(R.string.snackbar_no_grades); } @Override public void onRefreshSuccess(int number) { - onError(getString(R.string.snackbar_new_grade, number)); - } - - @Override - public void onError(String message) { - if (getActivity() != null) { - Snackbar.make(getActivity().findViewById(R.id.main_activity_view_pager), - message, Snackbar.LENGTH_LONG).show(); - } + showMessage(getString(R.string.snackbar_new_grade, number)); } @Override public void onDestroyView() { - presenter.onDestroy(); + presenter.detachView(); super.onDestroyView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesModule.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesModule.java new file mode 100644 index 000000000..edf00d3b8 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesModule.java @@ -0,0 +1,18 @@ +package io.github.wulkanowy.ui.main.grades; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; +import eu.davidea.flexibleadapter.FlexibleAdapter; + +@Module +public abstract class GradesModule { + + @Binds + abstract GradesContract.Presenter provideGradesPresenter(GradesPresenter gradesPresenter); + + @Provides + static FlexibleAdapter provideGradesAdapter() { + return new FlexibleAdapter<>(null); + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java index 493cc545f..ee6e0cb36 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java @@ -1,5 +1,7 @@ package io.github.wulkanowy.ui.main.grades; +import android.support.annotation.NonNull; + import com.crashlytics.android.answers.Answers; import com.crashlytics.android.answers.CustomEvent; @@ -41,8 +43,8 @@ public class GradesPresenter extends BasePresenter } @Override - public void onStart(GradesContract.View view, OnFragmentIsReadyListener listener) { - super.onStart(view); + public void attachView(@NonNull GradesContract.View view, OnFragmentIsReadyListener listener) { + super.attachView(view); this.listener = listener; if (getView().isMenuVisible()) { @@ -94,7 +96,7 @@ public class GradesPresenter extends BasePresenter refreshTask.setOnRefreshListener(this); refreshTask.execute(); } else { - getView().onNoNetworkError(); + getView().showNoNetworkMessage(); getView().hideRefreshingBar(); } } @@ -125,7 +127,7 @@ public class GradesPresenter extends BasePresenter getView().onRefreshSuccess(numberOfNewGrades); } } else { - getView().onError(getRepository().getResRepo().getErrorLoginMessage(exception)); + getView().showMessage(getRepository().getResRepo().getErrorLoginMessage(exception)); } getView().hideRefreshingBar(); @@ -183,9 +185,9 @@ public class GradesPresenter extends BasePresenter } @Override - public void onDestroy() { + public void detachView() { isFirstSight = false; cancelAsyncTasks(); - super.onDestroy(); + super.detachView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableContract.java index 57eca17e4..8344ad767 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableContract.java @@ -1,6 +1,7 @@ package io.github.wulkanowy.ui.main.timetable; -import io.github.wulkanowy.di.annotations.PerFragment; +import android.support.annotation.NonNull; + import io.github.wulkanowy.ui.base.BaseContract; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; @@ -21,12 +22,11 @@ public interface TimetableContract { void setThemeForTab(int position); } - @PerFragment interface Presenter extends BaseContract.Presenter { void onFragmentActivated(boolean isVisible); - void onStart(View view, OnFragmentIsReadyListener listener); + void attachView(@NonNull View view, OnFragmentIsReadyListener listener); void setRestoredPosition(int position); } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.java index 6c5fd501f..24960bd30 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.java @@ -11,14 +11,14 @@ import android.view.View; import android.view.ViewGroup; import javax.inject.Inject; +import javax.inject.Named; import butterknife.BindView; -import butterknife.ButterKnife; import io.github.wulkanowy.R; -import io.github.wulkanowy.di.component.FragmentComponent; import io.github.wulkanowy.ui.base.BaseFragment; import io.github.wulkanowy.ui.base.BasePagerAdapter; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; +import io.github.wulkanowy.ui.main.timetable.tab.TimetableTabFragment; public class TimetableFragment extends BaseFragment implements TimetableContract.View { @@ -30,6 +30,7 @@ public class TimetableFragment extends BaseFragment implements TimetableContract @BindView(R.id.timetable_fragment_tab_layout) TabLayout tabLayout; + @Named("Timetable") @Inject BasePagerAdapter pagerAdapter; @@ -40,16 +41,12 @@ public class TimetableFragment extends BaseFragment implements TimetableContract @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_timetable, container, false); + injectViews(view); - FragmentComponent component = getFragmentComponent(); - if (component != null) { - component.inject(this); - setButterKnife(ButterKnife.bind(this, view)); - presenter.onStart(this, (OnFragmentIsReadyListener) getActivity()); + presenter.attachView(this, (OnFragmentIsReadyListener) getActivity()); - if (savedInstanceState != null) { - presenter.setRestoredPosition(savedInstanceState.getInt(CURRENT_ITEM_KEY)); - } + if (savedInstanceState != null) { + presenter.setRestoredPosition(savedInstanceState.getInt(CURRENT_ITEM_KEY)); } return view; } @@ -91,14 +88,6 @@ public class TimetableFragment extends BaseFragment implements TimetableContract setTitle(getString(R.string.timetable_text)); } - @Override - public void onError(String message) { - if (getActivity() != null) { - Snackbar.make(getActivity().findViewById(R.id.main_activity_view_pager), - message, Snackbar.LENGTH_LONG).show(); - } - } - @Override public void onSaveInstanceState(Bundle outState) { outState.putInt(CURRENT_ITEM_KEY, viewPager.getCurrentItem()); @@ -107,7 +96,7 @@ public class TimetableFragment extends BaseFragment implements TimetableContract @Override public void onDestroyView() { - presenter.onDestroy(); + presenter.detachView(); super.onDestroyView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableModule.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableModule.java new file mode 100644 index 000000000..9ad1ee602 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableModule.java @@ -0,0 +1,32 @@ +package io.github.wulkanowy.ui.main.timetable; + +import javax.inject.Named; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; +import dagger.android.ContributesAndroidInjector; +import io.github.wulkanowy.di.scopes.PerChildFragment; +import io.github.wulkanowy.di.scopes.PerFragment; +import io.github.wulkanowy.ui.base.BasePagerAdapter; +import io.github.wulkanowy.ui.main.timetable.tab.TimetableTabFragment; +import io.github.wulkanowy.ui.main.timetable.tab.TimetableTabModule; + +@Module +public abstract class TimetableModule { + + @Named("Timetable") + @PerFragment + @Provides + static BasePagerAdapter providePagerAdapter(TimetableFragment fragment) { + return new BasePagerAdapter(fragment.getChildFragmentManager()); + } + + @PerFragment + @Binds + abstract TimetableContract.Presenter provideTimetablePresenter(TimetablePresenter timetablePresenter); + + @PerChildFragment + @ContributesAndroidInjector(modules = TimetableTabModule.class) + abstract TimetableTabFragment bindTimetableTabFragment(); +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetablePresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetablePresenter.java index d9c9c9c66..8c9bfabad 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetablePresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetablePresenter.java @@ -1,5 +1,7 @@ package io.github.wulkanowy.ui.main.timetable; +import android.support.annotation.NonNull; + import java.util.ArrayList; import java.util.List; @@ -31,8 +33,8 @@ public class TimetablePresenter extends BasePresenter } @Override - public void onStart(TimetableContract.View view, OnFragmentIsReadyListener listener) { - super.onStart(view); + public void attachView(@NonNull TimetableContract.View view, OnFragmentIsReadyListener listener) { + super.attachView(view); this.listener = listener; if (getView().isMenuVisible()) { @@ -64,7 +66,7 @@ public class TimetablePresenter extends BasePresenter } @Override - public void onDoInBackgroundLoading() throws Exception { + public void onDoInBackgroundLoading() { for (String date : dates) { getView().setTabDataToAdapter(date); } @@ -91,13 +93,13 @@ public class TimetablePresenter extends BasePresenter } @Override - public void onDestroy() { + public void detachView() { isFirstSight = false; if (loadingTask != null) { loadingTask.cancel(true); loadingTask = null; } - super.onDestroy(); + super.detachView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableHeaderItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeaderItem.java similarity index 98% rename from app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableHeaderItem.java rename to app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeaderItem.java index b98636b12..7e932f784 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableHeaderItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeaderItem.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.ui.main.timetable; +package io.github.wulkanowy.ui.main.timetable.tab; import android.content.Context; import android.content.res.TypedArray; diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableSubItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableSubItem.java similarity index 97% rename from app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableSubItem.java rename to app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableSubItem.java index a3e84dfa2..4d64b54b2 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableSubItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableSubItem.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.ui.main.timetable; +package io.github.wulkanowy.ui.main.timetable.tab; import android.content.Context; import android.graphics.Paint; @@ -21,6 +21,7 @@ import eu.davidea.flexibleadapter.items.IFlexible; import eu.davidea.viewholders.FlexibleViewHolder; import io.github.wulkanowy.R; import io.github.wulkanowy.data.db.dao.entities.TimetableLesson; +import io.github.wulkanowy.ui.main.timetable.TimetableDialogFragment; public class TimetableSubItem diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabContract.java similarity index 92% rename from app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabContract.java rename to app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabContract.java index 0d6bdf2a6..7eeb4b819 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabContract.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.ui.main.timetable; +package io.github.wulkanowy.ui.main.timetable.tab; import java.util.List; diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabFragment.java similarity index 78% rename from app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabFragment.java rename to app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabFragment.java index 53d9a67b4..6000cc6c2 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabFragment.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.ui.main.timetable; +package io.github.wulkanowy.ui.main.timetable.tab; import android.os.Bundle; import android.support.annotation.NonNull; @@ -16,11 +16,9 @@ import java.util.List; import javax.inject.Inject; import butterknife.BindView; -import butterknife.ButterKnife; import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager; import io.github.wulkanowy.R; -import io.github.wulkanowy.di.component.FragmentComponent; import io.github.wulkanowy.ui.base.BaseFragment; public class TimetableTabFragment extends BaseFragment implements TimetableTabContract.View, @@ -65,33 +63,27 @@ public class TimetableTabFragment extends BaseFragment implements TimetableTabCo @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_timetable_tab, container, false); + injectViews(view); - FragmentComponent component = getFragmentComponent(); - if (component != null) { - component.inject(this); - setButterKnife(ButterKnife.bind(this, view)); - - if (getArguments() != null) { - presenter.setArgumentDate(getArguments().getString(ARGUMENT_KEY)); - } - presenter.onStart(this); - presenter.onFragmentActivated(isFragmentVisible); + if (getArguments() != null) { + presenter.setArgumentDate(getArguments().getString(ARGUMENT_KEY)); } + presenter.attachView(this); + presenter.onFragmentActivated(isFragmentVisible); return view; } @Override - protected void setUpOnViewCreated(View fragmentView) { + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { adapter.setAutoCollapseOnExpand(true); adapter.setAutoScrollOnExpand(true); adapter.expandItemsAtStartUp(); - recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(fragmentView.getContext())); + recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(view.getContext())); recyclerView.setAdapter(adapter); refreshLayout.setColorSchemeResources(android.R.color.black); refreshLayout.setOnRefreshListener(this); - } @Override @@ -120,7 +112,7 @@ public class TimetableTabFragment extends BaseFragment implements TimetableTabCo @Override public void onRefreshSuccess() { - onError(R.string.sync_completed); + showMessage(R.string.sync_completed); } @Override @@ -138,17 +130,9 @@ public class TimetableTabFragment extends BaseFragment implements TimetableTabCo noItemView.setVisibility(show ? View.VISIBLE : View.INVISIBLE); } - @Override - public void onError(String message) { - if (getActivity() != null) { - Snackbar.make(getActivity().findViewById(R.id.main_activity_view_pager), - message, Snackbar.LENGTH_LONG).show(); - } - } - @Override public void onDestroyView() { - presenter.onDestroy(); + presenter.detachView(); super.onDestroyView(); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabModule.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabModule.java new file mode 100644 index 000000000..3e1645f31 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabModule.java @@ -0,0 +1,21 @@ +package io.github.wulkanowy.ui.main.timetable.tab; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; +import eu.davidea.flexibleadapter.FlexibleAdapter; +import io.github.wulkanowy.di.scopes.PerChildFragment; + +@Module +public abstract class TimetableTabModule { + + @PerChildFragment + @Binds + abstract TimetableTabContract.Presenter provideTimetableTabPresneter(TimetableTabPresenter timetableTabPresenter); + + @PerChildFragment + @Provides + static FlexibleAdapter provideTimetableAdapter() { + return new FlexibleAdapter<>(null); + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabPresenter.java similarity index 92% rename from app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabPresenter.java rename to app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabPresenter.java index ef41c4c75..51464b2e9 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableTabPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabPresenter.java @@ -1,4 +1,7 @@ -package io.github.wulkanowy.ui.main.timetable; +package io.github.wulkanowy.ui.main.timetable.tab; + + +import android.support.annotation.NonNull; import java.util.ArrayList; import java.util.List; @@ -36,8 +39,8 @@ public class TimetableTabPresenter extends BasePresenter { } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashModule.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashModule.java new file mode 100644 index 000000000..838b411d3 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashModule.java @@ -0,0 +1,13 @@ +package io.github.wulkanowy.ui.splash; + +import dagger.Binds; +import dagger.Module; +import io.github.wulkanowy.di.scopes.PerActivity; + +@Module +public abstract class SplashModule { + + @PerActivity + @Binds + abstract SplashContract.Presenter provideSplashPresenter(SplashPresenter splashPresenter); +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java index 8d20226fc..ff64b3cae 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java @@ -16,8 +16,8 @@ public class SplashPresenter extends BasePresenter } @Override - public void onStart(@NonNull SplashContract.View activity) { - super.onStart(activity); + public void attachView(@NonNull SplashContract.View view) { + super.attachView(view); getView().cancelNotifications(); if (getRepository().getSharedRepo().isUserLoggedIn()) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetFactory.java b/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetFactory.java index 78e80580a..2a858b909 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetFactory.java +++ b/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetFactory.java @@ -12,10 +12,7 @@ import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.List; -import javax.inject.Inject; - import io.github.wulkanowy.R; -import io.github.wulkanowy.WulkanowyApp; import io.github.wulkanowy.data.RepositoryContract; import io.github.wulkanowy.data.db.dao.entities.TimetableLesson; import io.github.wulkanowy.data.db.dao.entities.Week; @@ -23,22 +20,17 @@ import io.github.wulkanowy.utils.TimeUtils; public class TimetableWidgetFactory implements RemoteViewsService.RemoteViewsFactory { - private Context context; + private final Context context; private List lessonList = new ArrayList<>(); - @Inject - RepositoryContract repository; + private final RepositoryContract repository; - public TimetableWidgetFactory(Context context) { + public TimetableWidgetFactory(Context context, RepositoryContract repository) { this.context = context; + this.repository = repository; } - private void inject() { - if (repository == null) { - ((WulkanowyApp) context).getApplicationComponent().inject(this); - } - } @Override public void onCreate() { @@ -47,7 +39,6 @@ public class TimetableWidgetFactory implements RemoteViewsService.RemoteViewsFac @Override public void onDataSetChanged() { - inject(); lessonList = new ArrayList<>(); if (repository.getSharedRepo().isUserLoggedIn()) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetProvider.java b/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetProvider.java index d68c7e9a0..84f618a61 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetProvider.java +++ b/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetProvider.java @@ -11,8 +11,8 @@ import android.widget.RemoteViews; import javax.inject.Inject; +import dagger.android.AndroidInjection; import io.github.wulkanowy.R; -import io.github.wulkanowy.WulkanowyApp; import io.github.wulkanowy.data.RepositoryContract; import io.github.wulkanowy.services.widgets.TimetableWidgetServices; import io.github.wulkanowy.ui.main.MainActivity; @@ -26,7 +26,6 @@ public class TimetableWidgetProvider extends AppWidgetProvider { RepositoryContract repository; @Override - public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { inject(context); @@ -106,7 +105,7 @@ public class TimetableWidgetProvider extends AppWidgetProvider { private void inject(Context context) { if (repository == null) { - ((WulkanowyApp) context.getApplicationContext()).getApplicationComponent().inject(this); + AndroidInjection.inject(this, context); } } } From b4c765b482b1e401c1170ccb51cb241c1cb25a4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Mon, 28 May 2018 11:29:43 +0200 Subject: [PATCH 002/263] [API] Fix timetable endpoint (#125) --- .../main/java/io/github/wulkanowy/api/timetable/Timetable.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java b/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java index 1373aee91..4668149c3 100644 --- a/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java +++ b/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java @@ -19,7 +19,7 @@ import io.github.wulkanowy.api.generic.Week; public class Timetable { - private static final String TIMETABLE_PAGE_URL = "Lekcja.mvc/PlanLekcji?data="; + private static final String TIMETABLE_PAGE_URL = "Lekcja.mvc/PlanZajec?data="; private SnP snp; From d4b172e022f50a4ca74615dd9e623733691f49e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Mon, 28 May 2018 11:32:39 +0200 Subject: [PATCH 003/263] Version 0.4.5 --- app/build.gradle | 4 ++-- app/src/main/play/pl-PL/whatsnew | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 355596402..50677a7ae 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -41,8 +41,8 @@ android { testApplicationId "io.github.tests.wulkanowy" minSdkVersion 15 targetSdkVersion 26 - versionCode 12 - versionName "0.4.4" + versionCode 13 + versionName "0.4.5" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true playAccountConfig = playAccountConfigs.defaultAccountConfig diff --git a/app/src/main/play/pl-PL/whatsnew b/app/src/main/play/pl-PL/whatsnew index dd43c504b..b24edfaa4 100644 --- a/app/src/main/play/pl-PL/whatsnew +++ b/app/src/main/play/pl-PL/whatsnew @@ -1,5 +1,2 @@ -Wersja 0.4.4: -- naprawiono błędy w synchronizacji planu lekcji -- naprawiono błędy podczas pierwszego logowania -- naprawiono błąd podczas zmiany semestru -- kolejny raz poprawiono synchronizację w tle +Wersja 0.4.5: +- naprawiono logownie From 306092ce45f118fb32c3c2d6e4d284771eb7405c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Wed, 30 May 2018 11:57:29 +0200 Subject: [PATCH 004/263] Add mobile access API (#126) --- api/build.gradle | 29 +++++++++++ .../java/io/github/wulkanowy/api/Vulcan.java | 10 ++++ .../wulkanowy/api/mobile/RegisterDevice.kt | 33 +++++++++++++ .../wulkanowy/api/mobile/RegisteredDevices.kt | 48 +++++++++++++++++++ .../wulkanowy/api/mobile/RegisterDevice.kt | 17 +++++++ .../api/mobile/RegisteredDevicesListTest.kt | 37 ++++++++++++++ .../api/mobile/DostepMobilny-filled.html | 44 +++++++++++++++++ .../wulkanowy/api/mobile/Rejestruj.html | 26 ++++++++++ 8 files changed, 244 insertions(+) create mode 100644 api/src/main/java/io/github/wulkanowy/api/mobile/RegisterDevice.kt create mode 100644 api/src/main/java/io/github/wulkanowy/api/mobile/RegisteredDevices.kt create mode 100644 api/src/test/java/io/github/wulkanowy/api/mobile/RegisterDevice.kt create mode 100644 api/src/test/java/io/github/wulkanowy/api/mobile/RegisteredDevicesListTest.kt create mode 100644 api/src/test/resources/io/github/wulkanowy/api/mobile/DostepMobilny-filled.html create mode 100644 api/src/test/resources/io/github/wulkanowy/api/mobile/Rejestruj.html diff --git a/api/build.gradle b/api/build.gradle index 001d25791..f247baf10 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -1,4 +1,5 @@ apply plugin: 'java-library' +apply plugin: 'kotlin' apply plugin: 'org.sonarqube' apply plugin: 'jacoco' apply plugin: 'com.jfrog.bintray' @@ -32,6 +33,8 @@ dependencies { implementation "org.apache.commons:commons-lang3:$apacheLang" implementation "com.google.code.gson:gson:$gson" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" + testImplementation "junit:junit:$junit" testImplementation "org.mockito:mockito-core:$mockito" } @@ -115,3 +118,29 @@ artifacts { archives sourcesJar archives javadocJar } + +buildscript { + ext.kotlin_version = '1.2.41' + repositories { + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +repositories { + mavenCentral() +} + +compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} + +compileTestKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} diff --git a/api/src/main/java/io/github/wulkanowy/api/Vulcan.java b/api/src/main/java/io/github/wulkanowy/api/Vulcan.java index d90d38741..c8c4d2b0e 100644 --- a/api/src/main/java/io/github/wulkanowy/api/Vulcan.java +++ b/api/src/main/java/io/github/wulkanowy/api/Vulcan.java @@ -8,6 +8,8 @@ import io.github.wulkanowy.api.exams.ExamsWeek; import io.github.wulkanowy.api.grades.GradesList; import io.github.wulkanowy.api.grades.SubjectsList; import io.github.wulkanowy.api.messages.Messages; +import io.github.wulkanowy.api.mobile.RegisterDevice; +import io.github.wulkanowy.api.mobile.RegisteredDevices; import io.github.wulkanowy.api.notes.AchievementsList; import io.github.wulkanowy.api.notes.NotesList; import io.github.wulkanowy.api.school.SchoolInfo; @@ -108,6 +110,14 @@ public class Vulcan { return new FamilyInformation(getStudentAndParent()); } + public RegisteredDevices getRegisteredDevices() throws VulcanException, IOException { + return new RegisteredDevices(getStudentAndParent()); + } + + public RegisterDevice getRegisterDevice() throws VulcanException, IOException { + return new RegisterDevice(getStudentAndParent()); + } + public Messages getMessages() throws VulcanException { return new Messages(getClient()); } diff --git a/api/src/main/java/io/github/wulkanowy/api/mobile/RegisterDevice.kt b/api/src/main/java/io/github/wulkanowy/api/mobile/RegisterDevice.kt new file mode 100644 index 000000000..f0da01e9d --- /dev/null +++ b/api/src/main/java/io/github/wulkanowy/api/mobile/RegisterDevice.kt @@ -0,0 +1,33 @@ +package io.github.wulkanowy.api.mobile + +import io.github.wulkanowy.api.SnP +import org.jsoup.nodes.Element + +class RegisterDevice(private val snp: SnP) { + + companion object { + const val REGISTER_URL = "DostepMobilny.mvc/Rejestruj" + } + + data class Token( + val token: String, + val symbol: String, + val pin: String + ) + + fun getToken(): Token { + val form = snp.getSnPPageDocument(REGISTER_URL).selectFirst("#rejestracja-formularz") + + val fields = form.select(".blockElement") + + return Token( + getValue(fields[1]), + getValue(fields[2]), + getValue(fields[3]) + ) + } + + fun getValue(e: Element): String { + return e.text().split(":")[1].trim() + } +} diff --git a/api/src/main/java/io/github/wulkanowy/api/mobile/RegisteredDevices.kt b/api/src/main/java/io/github/wulkanowy/api/mobile/RegisteredDevices.kt new file mode 100644 index 000000000..cd08a5858 --- /dev/null +++ b/api/src/main/java/io/github/wulkanowy/api/mobile/RegisteredDevices.kt @@ -0,0 +1,48 @@ +package io.github.wulkanowy.api.mobile + +import io.github.wulkanowy.api.SnP +import java.text.SimpleDateFormat +import java.util.* + +class RegisteredDevices(private val snp: SnP) { + + companion object { + const val DEVICES_LIST_URL = "DostepMobilny.mvc" + } + + data class Device( + val name: String, + val system: String, + val date: String, + val id: Int + ) + + fun getList(): List { + val items = snp.getSnPPageDocument(DEVICES_LIST_URL).select("table tbody tr") + val devices: MutableList = mutableListOf() + + for (item in items) { + val cells = item.select("td") + val system = cells[0].text().split("(").last().removeSuffix(")") + + devices.add(Device( + cells[0].text().replace(" ($system)", ""), + system, + formatDate(cells[1].text()), + cells[2].select("a").attr("href") + .split("/").last().toInt() + )) + } + + return devices + } + + // TODO: Move to date utils + private fun formatDate(date: String): String { + val sdf = SimpleDateFormat("dd.MM.yyyy 'godz:' HH:mm:ss", Locale.ROOT) + val d = sdf.parse(date) + sdf.applyPattern("yyyy-MM-dd HH:mm:ss") + + return sdf.format(d) + } +} diff --git a/api/src/test/java/io/github/wulkanowy/api/mobile/RegisterDevice.kt b/api/src/test/java/io/github/wulkanowy/api/mobile/RegisterDevice.kt new file mode 100644 index 000000000..f67310c88 --- /dev/null +++ b/api/src/test/java/io/github/wulkanowy/api/mobile/RegisterDevice.kt @@ -0,0 +1,17 @@ +package io.github.wulkanowy.api.mobile + +import io.github.wulkanowy.api.StudentAndParentTestCase +import org.junit.Assert.assertEquals +import org.junit.Test + +class RegisterDeviceTest : StudentAndParentTestCase() { + + @Test + fun getTokenTest() { + val registration = RegisterDevice(getSnp("Rejestruj.html")) + + assertEquals("3S1A1B2C", registration.getToken().token) + assertEquals("Default", registration.getToken().symbol) + assertEquals("1234567", registration.getToken().pin) + } +} diff --git a/api/src/test/java/io/github/wulkanowy/api/mobile/RegisteredDevicesListTest.kt b/api/src/test/java/io/github/wulkanowy/api/mobile/RegisteredDevicesListTest.kt new file mode 100644 index 000000000..3cd8b97cc --- /dev/null +++ b/api/src/test/java/io/github/wulkanowy/api/mobile/RegisteredDevicesListTest.kt @@ -0,0 +1,37 @@ +package io.github.wulkanowy.api.mobile + +import io.github.wulkanowy.api.StudentAndParentTestCase +import org.junit.Assert.assertEquals +import org.junit.Test + +class RegisteredDevicesListTest : StudentAndParentTestCase() { + + private val filled = RegisteredDevices(getSnp("DostepMobilny-filled.html")) + + @Test + fun getListTest() { + assertEquals(2, filled.getList().size) + } + + @Test + fun getNameTest() { + assertEquals("google Android SDK built for x86", filled.getList()[0].name) + assertEquals("google (Android SDK) built for x86", filled.getList()[1].name) + } + + @Test + fun getSystemTest() { + assertEquals("Android 8.1.0", filled.getList()[0].system) + assertEquals("Android 8.1.0", filled.getList()[1].system) + } + + @Test + fun getDateTest() { + assertEquals("2018-01-20 22:35:30", filled.getList()[0].date) + } + + @Test + fun getIdTest() { + assertEquals(321, filled.getList()[0].id) + } +} diff --git a/api/src/test/resources/io/github/wulkanowy/api/mobile/DostepMobilny-filled.html b/api/src/test/resources/io/github/wulkanowy/api/mobile/DostepMobilny-filled.html new file mode 100644 index 000000000..9fbfd4039 --- /dev/null +++ b/api/src/test/resources/io/github/wulkanowy/api/mobile/DostepMobilny-filled.html @@ -0,0 +1,44 @@ + + + + + Witryna ucznia i rodzica – dostęp mobilny + + + +
+

Dostęp mobilny

+ +
+

Zarejestrowane urządzenia

+
+ + + + + + + + + + + + + + + + + + + + +
UrządzenieData rejestracji
google Android SDK built for x86 (Android 8.1.0)20.01.2018 godz: 22:35:30 + Wyrejestruj +
google (Android SDK) built for x86 (Android 8.1.0)20.01.2018 godz: 22:35:30 + Wyrejestruj +
+
+ +
wersja: 18.01.0001.27311
+ + diff --git a/api/src/test/resources/io/github/wulkanowy/api/mobile/Rejestruj.html b/api/src/test/resources/io/github/wulkanowy/api/mobile/Rejestruj.html new file mode 100644 index 000000000..15d08d07c --- /dev/null +++ b/api/src/test/resources/io/github/wulkanowy/api/mobile/Rejestruj.html @@ -0,0 +1,26 @@ + + + + + Witryna ucznia i rodzica – Rejestracja urządzenia mobilnego + + + +
+

Rejestracja urządzenia mobilnego

+
+ Za pomocą aplikacji "Dzienniczek+" zeskanuj kod QR. + Kod QR + Token: 3S1A1B2C + Symbol: Default + PIN: 1234567 +
+
+
wersja: 18.01.0001.27311
+ + From 228f680e5d461ddfca7bc336fabf00740a09c574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Thu, 31 May 2018 23:01:52 +0200 Subject: [PATCH 005/263] Hide empty fields in summary (#128) --- .../ui/main/grades/GradeHeaderItem.java | 111 +++++++++--------- 1 file changed, 53 insertions(+), 58 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradeHeaderItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradeHeaderItem.java index 5d0fd0731..33e961898 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradeHeaderItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradeHeaderItem.java @@ -118,57 +118,13 @@ public class GradeHeaderItem item.getFinalRating())); resetViews(); - toggleSummaryText(); toggleSubjectText(); + toggleSummary(); alertImage.setVisibility(isSubItemsReadAndSaveAlertView(subItems) ? View.INVISIBLE : View.VISIBLE); } - @Override - public void onClick(View view) { - super.onClick(view); - toggleSubjectText(); - toggleSummaryText(); - } - - private void toggleSummaryText() { - if (isSummaryToggleable()) { - if (isExpand()) { - AnimationUtils.slideDown(predictedText); - AnimationUtils.slideDown(finalText); - } else { - AnimationUtils.slideUp(predictedText); - AnimationUtils.slideUp(finalText); - } - } - } - - private void toggleSubjectText() { - if (isExpand()) { - subjectName.setMaxLines(3); - } else { - subjectName.setMaxLines(1); - } - } - - private void resetViews() { - subjectName.setMaxLines(1); - predictedText.setVisibility(View.GONE); - finalText.setVisibility(View.GONE); - } - - private boolean isSubItemsReadAndSaveAlertView(List subItems) { - boolean isRead = true; - - for (GradesSubItem gradesSubItem : subItems) { - isRead = gradesSubItem.getGrade().getRead(); - gradesSubItem.setSubjectAlertImage(alertImage); - } - - return isRead; - } - private String getGradesAverageString() { float average = GradeUtils.calculate(item.getGradeList()); @@ -179,26 +135,65 @@ public class GradeHeaderItem return resources.getString(R.string.info_average_grades, average); } + @Override + public void onClick(View view) { + super.onClick(view); + toggleSubjectText(); + toggleSummary(); + } + + private void resetViews() { + subjectName.setMaxLines(1); + setDefaultSummaryVisibility(predictedText, item.getPredictedRating()); + setDefaultSummaryVisibility(finalText, item.getFinalRating()); + } + + private void setDefaultSummaryVisibility(View view, String value) { + if (!"-".equals(value) && isShowSummary) { + view.setVisibility(View.VISIBLE); + } else { + view.setVisibility(View.GONE); + } + } + + private void toggleSubjectText() { + if (isExpand()) { + subjectName.setMaxLines(3); + } else { + subjectName.setMaxLines(1); + } + } + + private void toggleSummary() { + toggleSummaryView(predictedText, item.getPredictedRating(), isExpand()); + toggleSummaryView(finalText, item.getFinalRating(), isExpand()); + } + private boolean isExpand() { return adapter.isExpanded(getFlexibleAdapterPosition()); } - private boolean isSummaryToggleable() { - boolean isSummaryEmpty = true; - - if (!"-".equals(item.getPredictedRating()) || !"-".equals(item.getFinalRating())) { - isSummaryEmpty = false; + private void toggleSummaryView(View view, String value, boolean expand) { + if ("-".equals(value) || isShowSummary) { + return; } - if (isSummaryEmpty) { - return false; - } else if (isShowSummary) { - predictedText.setVisibility(View.VISIBLE); - finalText.setVisibility(View.VISIBLE); - - return false; + if (expand) { + AnimationUtils.slideDown(view); + } else { + AnimationUtils.slideUp(view); } - return true; + } + + private boolean isSubItemsReadAndSaveAlertView(List subItems) { + boolean isRead = true; + + for (GradesSubItem gradesSubItem : subItems) { + isRead = gradesSubItem.getGrade().getRead(); + gradesSubItem.setSubjectAlertImage(alertImage); + } + + return isRead; } } } From e2003e253821566632ff0b6fa03fe6d9c5046116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Thu, 31 May 2018 23:54:59 +0200 Subject: [PATCH 006/263] Expand current day on startup (#129) --- .../ui/main/timetable/TimetableFragment.java | 1 - .../timetable/tab/TimetableTabContract.java | 2 + .../timetable/tab/TimetableTabFragment.java | 7 +++- .../timetable/tab/TimetableTabPresenter.java | 24 +++++++---- .../io/github/wulkanowy/utils/TimeUtils.java | 9 +++++ .../github/wulkanowy/utils/TimeUtilsTest.java | 40 +++++++++++++++++++ 6 files changed, 74 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.java index 24960bd30..db3cc83c4 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/TimetableFragment.java @@ -3,7 +3,6 @@ package io.github.wulkanowy.ui.main.timetable; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.design.widget.Snackbar; import android.support.design.widget.TabLayout; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabContract.java index 7eeb4b819..254060a2e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabContract.java @@ -10,6 +10,8 @@ public interface TimetableTabContract { void updateAdapterList(List headerItems); + void expandItem(int item); + void onRefreshSuccess(); void hideRefreshingBar(); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabFragment.java index 6000cc6c2..e0a30e8d3 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabFragment.java @@ -3,7 +3,6 @@ package io.github.wulkanowy.ui.main.timetable.tab; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.design.widget.Snackbar; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; @@ -91,6 +90,12 @@ public class TimetableTabFragment extends BaseFragment implements TimetableTabCo adapter.updateDataSet(headerItems); } + @Override + public void expandItem(int position) { + adapter.expand(adapter.getItem(position), true); + recyclerView.scrollToPosition(position); + } + @Override public void setMenuVisibility(boolean menuVisible) { super.setMenuVisibility(menuVisible); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabPresenter.java index 51464b2e9..8841a7506 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabPresenter.java @@ -1,8 +1,9 @@ package io.github.wulkanowy.ui.main.timetable.tab; - import android.support.annotation.NonNull; +import org.threeten.bp.LocalDate; + import java.util.ArrayList; import java.util.List; @@ -13,7 +14,9 @@ import io.github.wulkanowy.data.db.dao.entities.Day; import io.github.wulkanowy.data.db.dao.entities.TimetableLesson; import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.ui.base.BasePresenter; +import io.github.wulkanowy.utils.AppConstant; import io.github.wulkanowy.utils.FabricUtils; +import io.github.wulkanowy.utils.TimeUtils; import io.github.wulkanowy.utils.async.AbstractTask; import io.github.wulkanowy.utils.async.AsyncListeners; @@ -48,8 +51,6 @@ public class TimetableTabPresenter extends BasePresenter Date: Fri, 1 Jun 2018 12:52:03 +0200 Subject: [PATCH 007/263] Move ticks converter to api (#130) --- .../io/github/wulkanowy/api/DateTimeUtils.kt | 49 +++++++++++++++++ .../java/io/github/wulkanowy/api/SnP.java | 5 ++ .../wulkanowy/api/StudentAndParent.java | 5 ++ .../api/attendance/AttendanceTable.java | 26 ++++----- .../github/wulkanowy/api/exams/ExamsWeek.java | 20 +++---- .../io/github/wulkanowy/api/generic/Day.java | 3 +- .../wulkanowy/api/{ => generic}/Diary.java | 2 +- .../api/{ => generic}/ParamItem.java | 4 +- .../wulkanowy/api/{ => generic}/Semester.java | 2 +- .../wulkanowy/api/{ => generic}/Student.java | 2 +- .../wulkanowy/api/grades/GradesList.java | 34 +++--------- .../wulkanowy/api/notes/AchievementsList.java | 6 +-- .../github/wulkanowy/api/notes/NotesList.java | 10 ++-- .../wulkanowy/api/school/SchoolInfo.java | 2 +- .../wulkanowy/api/school/TeachersInfo.java | 2 +- .../wulkanowy/api/timetable/Timetable.java | 21 +++----- .../github/wulkanowy/api/DateTimeUtilsTest.kt | 53 ++++++++++++++++++ .../wulkanowy/api/StudentAndParentTest.java | 2 + .../api/StudentAndParentTestCase.java | 2 + .../wulkanowy/api/grades/GradesListTest.java | 18 +++---- .../wulkanowy/api/notes/NotesListTest.java | 4 +- .../data/db/dao/migrations/Migration23.java | 2 +- .../wulkanowy/data/sync/AttendanceSync.java | 12 ++--- .../github/wulkanowy/data/sync/ExamsSync.java | 13 ++--- .../wulkanowy/data/sync/TimetableSync.java | 12 ++--- .../wulkanowy/utils/DataObjectConverter.java | 12 ++--- .../io/github/wulkanowy/utils/TimeUtils.java | 33 ------------ .../github/wulkanowy/utils/TimeUtilsTest.java | 54 +------------------ 28 files changed, 195 insertions(+), 215 deletions(-) create mode 100644 api/src/main/java/io/github/wulkanowy/api/DateTimeUtils.kt rename api/src/main/java/io/github/wulkanowy/api/{ => generic}/Diary.java (93%) rename api/src/main/java/io/github/wulkanowy/api/{ => generic}/ParamItem.java (67%) rename api/src/main/java/io/github/wulkanowy/api/{ => generic}/Semester.java (93%) rename api/src/main/java/io/github/wulkanowy/api/{ => generic}/Student.java (93%) create mode 100644 api/src/test/java/io/github/wulkanowy/api/DateTimeUtilsTest.kt diff --git a/api/src/main/java/io/github/wulkanowy/api/DateTimeUtils.kt b/api/src/main/java/io/github/wulkanowy/api/DateTimeUtils.kt new file mode 100644 index 000000000..bad4e97df --- /dev/null +++ b/api/src/main/java/io/github/wulkanowy/api/DateTimeUtils.kt @@ -0,0 +1,49 @@ +package io.github.wulkanowy.api + +import java.text.SimpleDateFormat +import java.util.* + +const val LOG_DATE_PATTERN = "dd.MM.yyyy" +const val API_DATE_PATTERN = "yyyy-MM-dd" + +const val TICKS_AT_EPOCH = 621355968000000000L +const val TICKS_PER_MILLISECOND = 10000 + +fun getFormattedDate(date: String): String { + return getFormattedDate(date, API_DATE_PATTERN) +} + +fun getFormattedDate(date: String, format: String): String { + val sdf = SimpleDateFormat(LOG_DATE_PATTERN, Locale.ROOT) + val d = sdf.parse(date) + sdf.applyPattern(format) + + return sdf.format(d) +} + +fun getDateAsTick(dateString: String?): String { + if (dateString.isNullOrEmpty()) { + return "" + } + + return getDateAsTick(dateString as String, API_DATE_PATTERN).toString() +} + +fun getDateAsTick(dateString: String, dateFormat: String): Long { + val format = SimpleDateFormat(dateFormat, Locale.ROOT) + format.timeZone = TimeZone.getTimeZone("UTC") + val dateObject = format.parse(dateString) + + return getDateAsTick(dateObject) +} + +fun getDateAsTick(date: Date): Long { + val calendar = Calendar.getInstance() + calendar.time = date + + return calendar.timeInMillis * TICKS_PER_MILLISECOND + TICKS_AT_EPOCH +} + +fun getDate(netTicks: Long): Date { + return Date((netTicks - TICKS_AT_EPOCH) / TICKS_PER_MILLISECOND) +} diff --git a/api/src/main/java/io/github/wulkanowy/api/SnP.java b/api/src/main/java/io/github/wulkanowy/api/SnP.java index 7f074071c..6747faf0e 100644 --- a/api/src/main/java/io/github/wulkanowy/api/SnP.java +++ b/api/src/main/java/io/github/wulkanowy/api/SnP.java @@ -6,6 +6,11 @@ import org.jsoup.nodes.Element; import java.io.IOException; import java.util.List; +import io.github.wulkanowy.api.generic.Diary; +import io.github.wulkanowy.api.generic.ParamItem; +import io.github.wulkanowy.api.generic.Semester; +import io.github.wulkanowy.api.generic.Student; + public interface SnP { String getSchoolID(); diff --git a/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java b/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java index 16ee002e0..a4b8fefa0 100644 --- a/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java +++ b/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java @@ -11,6 +11,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import io.github.wulkanowy.api.generic.Diary; +import io.github.wulkanowy.api.generic.ParamItem; +import io.github.wulkanowy.api.generic.Semester; +import io.github.wulkanowy.api.generic.Student; + public class StudentAndParent implements SnP { private static final String START_PAGE_URL = "{schema}://uonetplus.{host}/{symbol}/Start.mvc/Index"; diff --git a/api/src/main/java/io/github/wulkanowy/api/attendance/AttendanceTable.java b/api/src/main/java/io/github/wulkanowy/api/attendance/AttendanceTable.java index d81a30b2f..7caa70d80 100644 --- a/api/src/main/java/io/github/wulkanowy/api/attendance/AttendanceTable.java +++ b/api/src/main/java/io/github/wulkanowy/api/attendance/AttendanceTable.java @@ -4,12 +4,8 @@ import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Date; import java.util.List; -import java.util.Locale; import io.github.wulkanowy.api.SnP; import io.github.wulkanowy.api.VulcanException; @@ -17,6 +13,9 @@ import io.github.wulkanowy.api.generic.Day; import io.github.wulkanowy.api.generic.Lesson; import io.github.wulkanowy.api.generic.Week; +import static io.github.wulkanowy.api.DateTimeUtilsKt.getDateAsTick; +import static io.github.wulkanowy.api.DateTimeUtilsKt.getFormattedDate; + public class AttendanceTable { private final static String ATTENDANCE_PAGE_URL = "Frekwencja.mvc?data="; @@ -27,13 +26,12 @@ public class AttendanceTable { this.snp = snp; } - public Week getWeekTable() throws IOException, ParseException, VulcanException { + public Week getWeekTable() throws IOException, VulcanException { return getWeekTable(""); } - public Week getWeekTable(String tick) throws IOException, ParseException, VulcanException { - Element table = snp.getSnPPageDocument(ATTENDANCE_PAGE_URL + tick) - + public Week getWeekTable(String date) throws IOException, VulcanException { + Element table = snp.getSnPPageDocument(ATTENDANCE_PAGE_URL + getDateAsTick(date)) .select(".mainContainer .presentData").first(); Elements headerCells = table.select("thead th"); @@ -42,14 +40,10 @@ public class AttendanceTable { for (int i = 1; i < headerCells.size(); i++) { String[] dayHeaderCell = headerCells.get(i).html().split("
"); - SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy", Locale.ROOT); - Date d = sdf.parse(dayHeaderCell[1].trim()); - sdf.applyPattern("yyyy-MM-dd"); - - Day day = new Day(); - day.setDayName(dayHeaderCell[0]); - day.setDate(sdf.format(d)); - days.add(day); + days.add(new Day() + .setDayName(dayHeaderCell[0]) + .setDate(getFormattedDate(dayHeaderCell[1].trim())) + ); } Elements hoursInDays = table.select("tbody tr"); diff --git a/api/src/main/java/io/github/wulkanowy/api/exams/ExamsWeek.java b/api/src/main/java/io/github/wulkanowy/api/exams/ExamsWeek.java index c111ce848..391056ac9 100644 --- a/api/src/main/java/io/github/wulkanowy/api/exams/ExamsWeek.java +++ b/api/src/main/java/io/github/wulkanowy/api/exams/ExamsWeek.java @@ -6,17 +6,16 @@ import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Date; import java.util.List; -import java.util.Locale; import io.github.wulkanowy.api.SnP; import io.github.wulkanowy.api.VulcanException; import io.github.wulkanowy.api.generic.Week; +import static io.github.wulkanowy.api.DateTimeUtilsKt.getDateAsTick; +import static io.github.wulkanowy.api.DateTimeUtilsKt.getFormattedDate; + public class ExamsWeek { private static final String EXAMS_PAGE_URL = "Sprawdziany.mvc/Terminarz?rodzajWidoku=2&data="; @@ -27,12 +26,12 @@ public class ExamsWeek { this.snp = snp; } - public Week getCurrent() throws IOException, VulcanException, ParseException { + public Week getCurrent() throws IOException, VulcanException { return getWeek("", true); } - public Week getWeek(String tick, final boolean onlyNotEmpty) throws IOException, VulcanException, ParseException { - Document examsPage = snp.getSnPPageDocument(EXAMS_PAGE_URL + tick); + public Week getWeek(String date, final boolean onlyNotEmpty) throws IOException, VulcanException { + Document examsPage = snp.getSnPPageDocument(EXAMS_PAGE_URL + getDateAsTick(date)); Elements examsDays = examsPage.select(".mainContainer > div:not(.navigation)"); List days = new ArrayList<>(); @@ -71,11 +70,4 @@ public class ExamsWeek { .first().text().split(" ")[1])) .setDays(days); } - - private String getFormattedDate(String date) throws ParseException { - SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy", Locale.ROOT); - Date d = sdf.parse(date); - sdf.applyPattern("yyyy-MM-dd"); - return sdf.format(d); - } } diff --git a/api/src/main/java/io/github/wulkanowy/api/generic/Day.java b/api/src/main/java/io/github/wulkanowy/api/generic/Day.java index 5b9086a37..fbb5ee0a7 100644 --- a/api/src/main/java/io/github/wulkanowy/api/generic/Day.java +++ b/api/src/main/java/io/github/wulkanowy/api/generic/Day.java @@ -37,7 +37,8 @@ public class Day { return dayName; } - public void setDayName(String dayName) { + public Day setDayName(String dayName) { this.dayName = dayName; + return this; } } diff --git a/api/src/main/java/io/github/wulkanowy/api/Diary.java b/api/src/main/java/io/github/wulkanowy/api/generic/Diary.java similarity index 93% rename from api/src/main/java/io/github/wulkanowy/api/Diary.java rename to api/src/main/java/io/github/wulkanowy/api/generic/Diary.java index d7d09f9ce..5c7c8593b 100644 --- a/api/src/main/java/io/github/wulkanowy/api/Diary.java +++ b/api/src/main/java/io/github/wulkanowy/api/generic/Diary.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.api; +package io.github.wulkanowy.api.generic; public class Diary implements ParamItem { diff --git a/api/src/main/java/io/github/wulkanowy/api/ParamItem.java b/api/src/main/java/io/github/wulkanowy/api/generic/ParamItem.java similarity index 67% rename from api/src/main/java/io/github/wulkanowy/api/ParamItem.java rename to api/src/main/java/io/github/wulkanowy/api/generic/ParamItem.java index c830467ad..e7edfbf48 100644 --- a/api/src/main/java/io/github/wulkanowy/api/ParamItem.java +++ b/api/src/main/java/io/github/wulkanowy/api/generic/ParamItem.java @@ -1,6 +1,6 @@ -package io.github.wulkanowy.api; +package io.github.wulkanowy.api.generic; -interface ParamItem { +public interface ParamItem { ParamItem setId(String id); diff --git a/api/src/main/java/io/github/wulkanowy/api/Semester.java b/api/src/main/java/io/github/wulkanowy/api/generic/Semester.java similarity index 93% rename from api/src/main/java/io/github/wulkanowy/api/Semester.java rename to api/src/main/java/io/github/wulkanowy/api/generic/Semester.java index 31230f012..db4a724dd 100644 --- a/api/src/main/java/io/github/wulkanowy/api/Semester.java +++ b/api/src/main/java/io/github/wulkanowy/api/generic/Semester.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.api; +package io.github.wulkanowy.api.generic; public class Semester implements ParamItem { diff --git a/api/src/main/java/io/github/wulkanowy/api/Student.java b/api/src/main/java/io/github/wulkanowy/api/generic/Student.java similarity index 93% rename from api/src/main/java/io/github/wulkanowy/api/Student.java rename to api/src/main/java/io/github/wulkanowy/api/generic/Student.java index 8b22f1d83..4ed5dd373 100644 --- a/api/src/main/java/io/github/wulkanowy/api/Student.java +++ b/api/src/main/java/io/github/wulkanowy/api/generic/Student.java @@ -1,4 +1,4 @@ -package io.github.wulkanowy.api; +package io.github.wulkanowy.api.generic; public class Student implements ParamItem { diff --git a/api/src/main/java/io/github/wulkanowy/api/grades/GradesList.java b/api/src/main/java/io/github/wulkanowy/api/grades/GradesList.java index 936c1533b..cb9fe4657 100644 --- a/api/src/main/java/io/github/wulkanowy/api/grades/GradesList.java +++ b/api/src/main/java/io/github/wulkanowy/api/grades/GradesList.java @@ -5,42 +5,32 @@ import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Date; import java.util.List; -import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; import io.github.wulkanowy.api.SnP; import io.github.wulkanowy.api.VulcanException; +import static io.github.wulkanowy.api.DateTimeUtilsKt.getFormattedDate; + public class GradesList { private static final String GRADES_PAGE_URL = "Oceny/Wszystkie?details=2&okres="; private SnP snp; - private List grades = new ArrayList<>(); - public GradesList(SnP snp) { this.snp = snp; } - private String getGradesPageUrl() { - return GRADES_PAGE_URL; - } - - public List getAll() throws IOException, ParseException, VulcanException { - return getAll(""); - } - - public List getAll(String semester) throws IOException, ParseException, VulcanException { - Document gradesPage = snp.getSnPPageDocument(getGradesPageUrl() + semester); + public List getAll(String semester) throws IOException, VulcanException { + Document gradesPage = snp.getSnPPageDocument(GRADES_PAGE_URL + semester); Elements gradesRows = gradesPage.select(".ocenySzczegoly-table > tbody > tr"); + List grades = new ArrayList<>(); + for (Element row : gradesRows) { if ("Brak ocen".equals(row.select("td:nth-child(2)").text())) { continue; @@ -52,13 +42,13 @@ public class GradesList { return grades; } - private Grade getGrade(Element row) throws ParseException { + private Grade getGrade(Element row) { String descriptions = row.select("td:nth-child(3)").text(); String symbol = descriptions.split(", ")[0]; String description = descriptions.replaceFirst(Pattern.quote(symbol), "").replaceFirst(", ", ""); String color = getColor(row.select("td:nth-child(2) span.ocenaCzastkowa").attr("style")); - String date = formatDate(row.select("td:nth-child(5)").text()); + String date = getFormattedDate(row.select("td:nth-child(5)").text()); return new Grade() .setSubject(row.select("td:nth-child(1)").text()) @@ -82,12 +72,4 @@ public class GradesList { return color; } - - private String formatDate(String date) throws ParseException { - SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy", Locale.ROOT); - Date d = sdf.parse(date); - sdf.applyPattern("yyyy-MM-dd"); - - return sdf.format(d); - } } diff --git a/api/src/main/java/io/github/wulkanowy/api/notes/AchievementsList.java b/api/src/main/java/io/github/wulkanowy/api/notes/AchievementsList.java index 11d013429..346df832e 100644 --- a/api/src/main/java/io/github/wulkanowy/api/notes/AchievementsList.java +++ b/api/src/main/java/io/github/wulkanowy/api/notes/AchievementsList.java @@ -14,9 +14,7 @@ public class AchievementsList { private static final String NOTES_PAGE_URL = "UwagiOsiagniecia.mvc/Wszystkie"; - private SnP snp = null; - - private List achievements = new ArrayList<>(); + private SnP snp; public AchievementsList(SnP snp) { this.snp = snp; @@ -27,6 +25,8 @@ public class AchievementsList { .select(".mainContainer > div").get(1); Elements items = pageFragment.select("article"); + List achievements = new ArrayList<>(); + for (Element item : items) { achievements.add(item.text()); } diff --git a/api/src/main/java/io/github/wulkanowy/api/notes/NotesList.java b/api/src/main/java/io/github/wulkanowy/api/notes/NotesList.java index 0c8a30b6b..54f57edf4 100644 --- a/api/src/main/java/io/github/wulkanowy/api/notes/NotesList.java +++ b/api/src/main/java/io/github/wulkanowy/api/notes/NotesList.java @@ -10,13 +10,13 @@ import java.util.List; import io.github.wulkanowy.api.SnP; import io.github.wulkanowy.api.VulcanException; +import static io.github.wulkanowy.api.DateTimeUtilsKt.getFormattedDate; + public class NotesList { private static final String NOTES_PAGE_URL = "UwagiOsiagniecia.mvc/Wszystkie"; - private SnP snp = null; - - private List notes = new ArrayList<>(); + private SnP snp; public NotesList(SnP snp) { this.snp = snp; @@ -28,10 +28,12 @@ public class NotesList { Elements items = pageFragment.select("article"); Elements dates = pageFragment.select("h2"); + List notes = new ArrayList<>(); + int index = 0; for (Element item : items) { notes.add(new Note() - .setDate(dates.get(index++).text()) + .setDate(getFormattedDate(dates.get(index++).text())) .setTeacher(snp.getRowDataChildValue(item, 1)) .setCategory(snp.getRowDataChildValue(item, 2)) .setContent(snp.getRowDataChildValue(item, 3)) diff --git a/api/src/main/java/io/github/wulkanowy/api/school/SchoolInfo.java b/api/src/main/java/io/github/wulkanowy/api/school/SchoolInfo.java index 51a7278bd..f0dcd43de 100644 --- a/api/src/main/java/io/github/wulkanowy/api/school/SchoolInfo.java +++ b/api/src/main/java/io/github/wulkanowy/api/school/SchoolInfo.java @@ -11,7 +11,7 @@ public class SchoolInfo { private static final String SCHOOL_PAGE_URL = "Szkola.mvc/Nauczyciele"; - private SnP snp = null; + private SnP snp; public SchoolInfo(SnP snp) { this.snp = snp; diff --git a/api/src/main/java/io/github/wulkanowy/api/school/TeachersInfo.java b/api/src/main/java/io/github/wulkanowy/api/school/TeachersInfo.java index bbf5f5d7f..ec8429bd9 100644 --- a/api/src/main/java/io/github/wulkanowy/api/school/TeachersInfo.java +++ b/api/src/main/java/io/github/wulkanowy/api/school/TeachersInfo.java @@ -15,7 +15,7 @@ public class TeachersInfo { private static final String SCHOOL_PAGE_URL = "Szkola.mvc/Nauczyciele"; - private SnP snp = null; + private SnP snp; public TeachersInfo(SnP snp) { this.snp = snp; diff --git a/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java b/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java index 4668149c3..8a2b9e14e 100644 --- a/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java +++ b/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java @@ -5,18 +5,17 @@ import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.IOException; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Date; import java.util.List; -import java.util.Locale; import io.github.wulkanowy.api.SnP; import io.github.wulkanowy.api.VulcanException; import io.github.wulkanowy.api.generic.Lesson; import io.github.wulkanowy.api.generic.Week; +import static io.github.wulkanowy.api.DateTimeUtilsKt.getFormattedDate; +import static io.github.wulkanowy.api.DateTimeUtilsKt.getDateAsTick; + public class Timetable { private static final String TIMETABLE_PAGE_URL = "Lekcja.mvc/PlanZajec?data="; @@ -27,12 +26,12 @@ public class Timetable { this.snp = snp; } - public Week getWeekTable() throws IOException, ParseException, VulcanException { + public Week getWeekTable() throws IOException, VulcanException { return getWeekTable(""); } - public Week getWeekTable(final String tick) throws IOException, ParseException, VulcanException { - Element table = snp.getSnPPageDocument(TIMETABLE_PAGE_URL + tick) + public Week getWeekTable(final String date) throws IOException, VulcanException { + Element table = snp.getSnPPageDocument(TIMETABLE_PAGE_URL + getDateAsTick(date)) .select(".mainContainer .presentData").first(); List days = getDays(table.select("thead th")); @@ -44,19 +43,15 @@ public class Timetable { .setDays(days); } - private List getDays(Elements tableHeaderCells) throws ParseException { + private List getDays(Elements tableHeaderCells) { List days = new ArrayList<>(); for (int i = 2; i < 7; i++) { String[] dayHeaderCell = tableHeaderCells.get(i).html().split("
"); - SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy", Locale.ROOT); - Date d = sdf.parse(dayHeaderCell[1].trim()); - sdf.applyPattern("yyyy-MM-dd"); - TimetableDay day = new TimetableDay(); day.setDayName(dayHeaderCell[0]); - day.setDate(sdf.format(d)); + day.setDate(getFormattedDate(dayHeaderCell[1].trim())); if (tableHeaderCells.get(i).hasClass("free-day")) { day.setFreeDay(true); diff --git a/api/src/test/java/io/github/wulkanowy/api/DateTimeUtilsTest.kt b/api/src/test/java/io/github/wulkanowy/api/DateTimeUtilsTest.kt new file mode 100644 index 000000000..1105b2a72 --- /dev/null +++ b/api/src/test/java/io/github/wulkanowy/api/DateTimeUtilsTest.kt @@ -0,0 +1,53 @@ +package io.github.wulkanowy.api + +import org.junit.Assert +import org.junit.Test +import java.text.ParseException +import java.text.SimpleDateFormat +import java.util.* + +class DateTimeUtilsTest { + + @Test + fun getTicksDateObjectTest() { + val format = SimpleDateFormat("dd.MM.yyyy", Locale.ROOT) + format.timeZone = TimeZone.getTimeZone("UTC") + val date = format.parse("31.07.2017") + + Assert.assertEquals(636370560000000000L, getDateAsTick(date)) + + val calendar = Calendar.getInstance() + calendar.time = date + calendar.add(Calendar.DAY_OF_YEAR, -14) + val dateTwoWeekBefore = calendar.time + + Assert.assertEquals(636358464000000000L, getDateAsTick(dateTwoWeekBefore)) + } + + @Test(expected = ParseException::class) + fun getTicsStringInvalidFormatTest() { + Assert.assertEquals(636370560000000000L, getDateAsTick("31.07.2017", "dd.MMM.yyyy")) + } + + @Test + fun getTicsStringFormatTest() { + Assert.assertEquals(636370560000000000L, getDateAsTick("31.07.2017", "dd.MM.yyyy")) + } + + @Test + fun getTicsStringTest() { + Assert.assertEquals("636370560000000000", getDateAsTick("2017-07-31")) + Assert.assertEquals("636334272000000000", getDateAsTick("2017-06-19")) + Assert.assertEquals("636189120000000000", getDateAsTick("2017-01-02")) + Assert.assertEquals("636080256000000000", getDateAsTick("2016-08-29")) + } + + @Test + fun getDateTest() { + val format = SimpleDateFormat("dd.MM.yyyy", Locale.ROOT) + format.timeZone = TimeZone.getTimeZone("UTC") + val date = format.parse("31.07.2017") + + Assert.assertEquals(date, getDate(636370560000000000L)) + } +} diff --git a/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java b/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java index 387d18f58..1b6f7a91b 100644 --- a/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java +++ b/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java @@ -11,6 +11,8 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import io.github.wulkanowy.api.generic.Semester; + public class StudentAndParentTest { private Client client; diff --git a/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTestCase.java b/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTestCase.java index 8d32291fe..764e8009e 100644 --- a/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTestCase.java +++ b/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTestCase.java @@ -5,6 +5,8 @@ import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.mockito.Mockito; +import io.github.wulkanowy.api.generic.Semester; + public abstract class StudentAndParentTestCase { protected StudentAndParent getSnp(String fixtureFileName) throws Exception { diff --git a/api/src/test/java/io/github/wulkanowy/api/grades/GradesListTest.java b/api/src/test/java/io/github/wulkanowy/api/grades/GradesListTest.java index 6eff84c95..deab7617c 100644 --- a/api/src/test/java/io/github/wulkanowy/api/grades/GradesListTest.java +++ b/api/src/test/java/io/github/wulkanowy/api/grades/GradesListTest.java @@ -19,12 +19,12 @@ public class GradesListTest extends StudentAndParentTestCase { @Test public void getAllTest() throws Exception { - Assert.assertEquals(7, filled.getAll().size()); // 2 items are skipped + Assert.assertEquals(7, filled.getAll("").size()); // 2 items are skipped } @Test public void getSubjectTest() throws Exception { - List list = filled.getAll(); + List list = filled.getAll(""); Assert.assertEquals("Zajęcia z wychowawcą", list.get(0).getSubject()); Assert.assertEquals("Język angielski", list.get(3).getSubject()); @@ -34,7 +34,7 @@ public class GradesListTest extends StudentAndParentTestCase { @Test public void getValueTest() throws Exception { - List list = filled.getAll(); + List list = filled.getAll(""); Assert.assertEquals("5", list.get(0).getValue()); Assert.assertEquals("5", list.get(3).getValue()); @@ -44,7 +44,7 @@ public class GradesListTest extends StudentAndParentTestCase { @Test public void getColorTest() throws Exception { - List list = filled.getAll(); + List list = filled.getAll(""); Assert.assertEquals("000000", list.get(0).getColor()); Assert.assertEquals("1289F7", list.get(3).getColor()); @@ -54,7 +54,7 @@ public class GradesListTest extends StudentAndParentTestCase { @Test public void getSymbolTest() throws Exception { - List list = filled.getAll(); + List list = filled.getAll(""); Assert.assertEquals("A1", list.get(0).getSymbol()); Assert.assertEquals("BW3", list.get(3).getSymbol()); @@ -65,7 +65,7 @@ public class GradesListTest extends StudentAndParentTestCase { @Test public void getDescriptionTest() throws Exception { - List list = filled.getAll(); + List list = filled.getAll(""); Assert.assertEquals("Dzień Kobiet w naszej klasie", list.get(0).getDescription()); Assert.assertEquals("Writing", list.get(3).getDescription()); @@ -76,7 +76,7 @@ public class GradesListTest extends StudentAndParentTestCase { @Test public void getWeightTest() throws Exception { - List list = filled.getAll(); + List list = filled.getAll(""); Assert.assertEquals("1,00", list.get(0).getWeight()); Assert.assertEquals("3,00", list.get(3).getWeight()); @@ -86,7 +86,7 @@ public class GradesListTest extends StudentAndParentTestCase { @Test public void getDateTest() throws Exception { - List list = filled.getAll(); + List list = filled.getAll(""); Assert.assertEquals("2017-03-21", list.get(0).getDate()); Assert.assertEquals("2017-06-02", list.get(3).getDate()); @@ -96,7 +96,7 @@ public class GradesListTest extends StudentAndParentTestCase { @Test public void getTeacherTest() throws Exception { - List list = filled.getAll(); + List list = filled.getAll(""); Assert.assertEquals("Patryk Maciejewski", list.get(0).getTeacher()); Assert.assertEquals("Oliwia Woźniak", list.get(3).getTeacher()); diff --git a/api/src/test/java/io/github/wulkanowy/api/notes/NotesListTest.java b/api/src/test/java/io/github/wulkanowy/api/notes/NotesListTest.java index d76c06486..304eb01a8 100644 --- a/api/src/test/java/io/github/wulkanowy/api/notes/NotesListTest.java +++ b/api/src/test/java/io/github/wulkanowy/api/notes/NotesListTest.java @@ -30,8 +30,8 @@ public class NotesListTest extends StudentAndParentTestCase { public void getDateTest() throws Exception { List filledList = filled.getAllNotes(); - Assert.assertEquals("06.06.2017", filledList.get(0).getDate()); - Assert.assertEquals("01.10.2016", filledList.get(2).getDate()); + Assert.assertEquals("2017-06-06", filledList.get(0).getDate()); + Assert.assertEquals("2016-10-01", filledList.get(2).getDate()); } @Test diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration23.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration23.java index b32c6261b..97b575a02 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration23.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration23.java @@ -9,7 +9,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import io.github.wulkanowy.api.Diary; +import io.github.wulkanowy.api.generic.Diary; import io.github.wulkanowy.api.Vulcan; import io.github.wulkanowy.data.db.dao.DbHelper; import io.github.wulkanowy.data.db.shared.SharedPrefContract; diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/AttendanceSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/AttendanceSync.java index 59a6e1a3b..9f379be60 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/AttendanceSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/AttendanceSync.java @@ -1,7 +1,6 @@ package io.github.wulkanowy.data.sync; import java.io.IOException; -import java.text.ParseException; import java.util.ArrayList; import java.util.List; @@ -20,7 +19,6 @@ import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.data.db.dao.entities.WeekDao; import io.github.wulkanowy.utils.DataObjectConverter; import io.github.wulkanowy.utils.LogUtils; -import io.github.wulkanowy.utils.TimeUtils; @Singleton public class AttendanceSync { @@ -37,10 +35,10 @@ public class AttendanceSync { this.vulcan = vulcan; } - public void syncAttendance(long diaryId, String date) throws IOException, ParseException, VulcanException { + public void syncAttendance(long diaryId, String date) throws IOException, VulcanException { this.diaryId = diaryId; - io.github.wulkanowy.api.generic.Week weekApi = getWeekFromApi(getNormalizedDate(date)); + io.github.wulkanowy.api.generic.Week weekApi = getWeekFromApi(date); Week weekDb = getWeekFromDb(weekApi.getStartDayDate()); long weekId = updateWeekInDb(weekDb, weekApi); @@ -52,12 +50,8 @@ public class AttendanceSync { LogUtils.debug("Synchronization attendance lessons (amount = " + lessonList.size() + ")"); } - private String getNormalizedDate(String date) throws ParseException { - return null != date ? String.valueOf(TimeUtils.getNetTicks(date)) : ""; - } - private io.github.wulkanowy.api.generic.Week getWeekFromApi(String date) - throws IOException, ParseException, VulcanException { + throws IOException, VulcanException { return vulcan.getAttendanceTable().getWeekTable(date); } diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java index 53470882d..85b4dac40 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java @@ -1,7 +1,6 @@ package io.github.wulkanowy.data.sync; import java.io.IOException; -import java.text.ParseException; import java.util.ArrayList; import java.util.List; @@ -19,7 +18,6 @@ import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.data.db.dao.entities.WeekDao; import io.github.wulkanowy.utils.DataObjectConverter; import io.github.wulkanowy.utils.LogUtils; -import io.github.wulkanowy.utils.TimeUtils; public class ExamsSync { @@ -35,11 +33,10 @@ public class ExamsSync { this.vulcan = vulcan; } - public void syncExams(long diaryId, String date) throws IOException, VulcanException, - ParseException { + public void syncExams(long diaryId, String date) throws IOException, VulcanException { this.diaryId = diaryId; - io.github.wulkanowy.api.generic.Week weekApi = getWeekFromApi(getNormalizedDate(date)); + io.github.wulkanowy.api.generic.Week weekApi = getWeekFromApi(date); Week weekDb = getWeekFromDb(weekApi.getStartDayDate()); long weekId = updateWeekInDb(weekDb, weekApi); @@ -59,7 +56,7 @@ public class ExamsSync { } private io.github.wulkanowy.api.generic.Week getWeekFromApi(String date) - throws VulcanException, IOException, ParseException { + throws VulcanException, IOException { return vulcan.getExamsList().getWeek(date, true); } @@ -77,10 +74,6 @@ public class ExamsSync { return daoSession.getWeekDao().insert(weekApiEntity); } - private String getNormalizedDate(String date) throws ParseException { - return null != date ? String.valueOf(TimeUtils.getNetTicks(date)) : ""; - } - private Day getDayFromDb(String date, long weekId) { return daoSession.getDayDao().queryBuilder().where( DayDao.Properties.WeekId.eq(weekId), diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java index 3fe22afff..309403c88 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java @@ -3,7 +3,6 @@ package io.github.wulkanowy.data.sync; import org.apache.commons.collections4.CollectionUtils; import java.io.IOException; -import java.text.ParseException; import java.util.ArrayList; import java.util.List; @@ -22,7 +21,6 @@ import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.data.db.dao.entities.WeekDao; import io.github.wulkanowy.utils.DataObjectConverter; import io.github.wulkanowy.utils.LogUtils; -import io.github.wulkanowy.utils.TimeUtils; @Singleton public class TimetableSync { @@ -39,10 +37,10 @@ public class TimetableSync { this.vulcan = vulcan; } - public void syncTimetable(long diaryId, String date) throws IOException, ParseException, VulcanException { + public void syncTimetable(long diaryId, String date) throws IOException, VulcanException { this.diaryId = diaryId; - io.github.wulkanowy.api.generic.Week weekApi = getWeekFromApi(getNormalizedDate(date)); + io.github.wulkanowy.api.generic.Week weekApi = getWeekFromApi(date); Week weekDb = getWeekFromDb(weekApi.getStartDayDate()); long weekId = updateWeekInDb(weekDb, weekApi); @@ -54,12 +52,8 @@ public class TimetableSync { LogUtils.debug("Synchronization timetable lessons (amount = " + lessonList.size() + ")"); } - private String getNormalizedDate(String date) throws ParseException { - return null != date ? String.valueOf(TimeUtils.getNetTicks(date)) : ""; - } - private io.github.wulkanowy.api.generic.Week getWeekFromApi(String date) - throws IOException, ParseException, VulcanException { + throws IOException, VulcanException { return vulcan.getTimetable().getWeekTable(date); } diff --git a/app/src/main/java/io/github/wulkanowy/utils/DataObjectConverter.java b/app/src/main/java/io/github/wulkanowy/utils/DataObjectConverter.java index 3f733ad6d..1747fc265 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/DataObjectConverter.java +++ b/app/src/main/java/io/github/wulkanowy/utils/DataObjectConverter.java @@ -21,10 +21,10 @@ public final class DataObjectConverter { throw new IllegalStateException("Utility class"); } - public static List studentsToStudentEntities(List students, Long symbolId) { + public static List studentsToStudentEntities(List students, Long symbolId) { List studentList = new ArrayList<>(); - for (io.github.wulkanowy.api.Student student : students) { + for (io.github.wulkanowy.api.generic.Student student : students) { studentList.add(new Student() .setName(student.getName()) .setCurrent(student.isCurrent()) @@ -36,10 +36,10 @@ public final class DataObjectConverter { return studentList; } - public static List diariesToDiaryEntities(List diaryList, Long studentId) { + public static List diariesToDiaryEntities(List diaryList, Long studentId) { List diaryEntityList = new ArrayList<>(); - for (io.github.wulkanowy.api.Diary diary : diaryList) { + for (io.github.wulkanowy.api.generic.Diary diary : diaryList) { diaryEntityList.add(new Diary() .setStudentId(studentId) .setValue(diary.getId()) @@ -50,10 +50,10 @@ public final class DataObjectConverter { return diaryEntityList; } - public static List semestersToSemesterEntities(List semesters, long diaryId) { + public static List semestersToSemesterEntities(List semesters, long diaryId) { List semesterList = new ArrayList<>(); - for (io.github.wulkanowy.api.Semester semester : semesters) { + for (io.github.wulkanowy.api.generic.Semester semester : semesters) { semesterList.add(new Semester() .setDiaryId(diaryId) .setName(semester.getName()) diff --git a/app/src/main/java/io/github/wulkanowy/utils/TimeUtils.java b/app/src/main/java/io/github/wulkanowy/utils/TimeUtils.java index eaed222e2..a305bc6d1 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/TimeUtils.java +++ b/app/src/main/java/io/github/wulkanowy/utils/TimeUtils.java @@ -4,54 +4,21 @@ import org.threeten.bp.DayOfWeek; import org.threeten.bp.LocalDate; import org.threeten.bp.format.DateTimeFormatter; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; import java.util.List; -import java.util.Locale; -import java.util.TimeZone; public final class TimeUtils { - private static final long TICKS_AT_EPOCH = 621355968000000000L; - - private static final long TICKS_PER_MILLISECOND = 10000; - private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(AppConstant.DATE_PATTERN); private TimeUtils() { throw new IllegalStateException("Utility class"); } - public static long getNetTicks(Date date) { - Calendar calendar = Calendar.getInstance(); - calendar.setTime(date); - - return (calendar.getTimeInMillis() * TICKS_PER_MILLISECOND) + TICKS_AT_EPOCH; - } - - public static long getNetTicks(String dateString) throws ParseException { - return getNetTicks(dateString, AppConstant.DATE_PATTERN); - } - - public static long getNetTicks(String dateString, String dateFormat) throws ParseException { - SimpleDateFormat format = new SimpleDateFormat(dateFormat, Locale.ROOT); - format.setTimeZone(TimeZone.getTimeZone("UTC")); - Date dateObject = format.parse(dateString); - - return getNetTicks(dateObject); - } - public static LocalDate getParsedDate(String dateString, String dateFormat) { return LocalDate.parse(dateString, DateTimeFormatter.ofPattern(dateFormat)); } - public static Date getDate(long netTicks) { - return new Date((netTicks - TICKS_AT_EPOCH) / TICKS_PER_MILLISECOND); - } - public static List getMondaysFromCurrentSchoolYear() { LocalDate startDate = LocalDate.of(getCurrentSchoolYear(), 9, 1); LocalDate endDate = LocalDate.of(getCurrentSchoolYear() + 1, 8, 31); diff --git a/app/src/test/java/io/github/wulkanowy/utils/TimeUtilsTest.java b/app/src/test/java/io/github/wulkanowy/utils/TimeUtilsTest.java index 41e606891..e216392e7 100644 --- a/app/src/test/java/io/github/wulkanowy/utils/TimeUtilsTest.java +++ b/app/src/test/java/io/github/wulkanowy/utils/TimeUtilsTest.java @@ -4,62 +4,12 @@ import org.junit.Assert; import org.junit.Test; import org.threeten.bp.LocalDate; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; - public class TimeUtilsTest { - @Test - public void getTicksDateObjectTest() throws Exception { - SimpleDateFormat format = new SimpleDateFormat("dd.MM.yyyy", Locale.ROOT); - format.setTimeZone(TimeZone.getTimeZone("UTC")); - Date date = format.parse("31.07.2017"); - - Assert.assertEquals(636370560000000000L, TimeUtils.getNetTicks(date)); - - Calendar calendar = Calendar.getInstance(); - calendar.setTime(date); - calendar.add(Calendar.DAY_OF_YEAR, -14); - Date dateTwoWeekBefore = calendar.getTime(); - - Assert.assertEquals(636358464000000000L, TimeUtils.getNetTicks(dateTwoWeekBefore)); - } - - @Test(expected = ParseException.class) - public void getTicsStringInvalidFormatTest() throws Exception { - Assert.assertEquals(636370560000000000L, TimeUtils.getNetTicks("31.07.2017", "dd.MMM.yyyy")); - } - - @Test - public void getTicsStringFormatTest() throws Exception { - Assert.assertEquals(636370560000000000L, TimeUtils.getNetTicks("31.07.2017", "dd.MM.yyyy")); - } - - @Test - public void getTicsStringTest() throws Exception { - Assert.assertEquals(636370560000000000L, TimeUtils.getNetTicks("2017-07-31")); - Assert.assertEquals(636334272000000000L, TimeUtils.getNetTicks("2017-06-19")); - Assert.assertEquals(636189120000000000L, TimeUtils.getNetTicks("2017-01-02")); - Assert.assertEquals(636080256000000000L, TimeUtils.getNetTicks("2016-08-29")); - } - @Test public void getParsedDateTest() { - Assert.assertEquals(LocalDate.of(1970, 1, 1), TimeUtils.getParsedDate("1970-01-01", "yyyy-MM-dd")); - } - - @Test - public void getDateTest() throws Exception { - DateFormat format = new SimpleDateFormat("dd.MM.yyyy", Locale.ROOT); - format.setTimeZone(TimeZone.getTimeZone("UTC")); - Date date = format.parse("31.07.2017"); - - Assert.assertEquals(date, TimeUtils.getDate(636370560000000000L)); + Assert.assertEquals(LocalDate.of(1970, 1, 1), + TimeUtils.getParsedDate("1970-01-01", "yyyy-MM-dd")); } @Test From 0e16519baf03bcb6d49bbb54f9cbdba95e4f45ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Mon, 4 Jun 2018 21:47:46 +0200 Subject: [PATCH 008/263] Add a summary of grades (#127) --- ...eHeaderItem.java => AttendanceHeader.java} | 8 +- .../attendance/tab/AttendanceSubItem.java | 4 +- .../attendance/tab/AttendanceTabContract.java | 2 +- .../attendance/tab/AttendanceTabFragment.java | 4 +- .../attendance/tab/AttendanceTabModule.java | 2 +- .../tab/AttendanceTabPresenter.java | 4 +- ...{ExamsHeaderItem.java => ExamsHeader.java} | 6 +- .../ui/main/exams/tab/ExamsSubItem.java | 4 +- .../ui/main/exams/tab/ExamsTabPresenter.java | 2 +- .../ui/main/grades/GradesContract.java | 6 +- .../ui/main/grades/GradesDialogFragment.java | 2 +- .../ui/main/grades/GradesFragment.java | 92 ++++++--- ...GradeHeaderItem.java => GradesHeader.java} | 12 +- .../ui/main/grades/GradesModule.java | 7 +- .../ui/main/grades/GradesPresenter.java | 55 +++++- .../ui/main/grades/GradesSubItem.java | 6 +- .../ui/main/grades/GradesSummaryHeader.java | 87 ++++++++ .../ui/main/grades/GradesSummarySubItem.java | 83 ++++++++ ...leHeaderItem.java => TimetableHeader.java} | 8 +- .../main/timetable/tab/TimetableSubItem.java | 4 +- .../timetable/tab/TimetableTabContract.java | 2 +- .../timetable/tab/TimetableTabFragment.java | 4 +- .../timetable/tab/TimetableTabModule.java | 2 +- .../timetable/tab/TimetableTabPresenter.java | 4 +- .../io/github/wulkanowy/utils/GradeUtils.java | 121 +++++++++--- .../res/drawable/ic_action_menu_semester.xml | 10 + .../res/drawable/ic_action_menu_summary.xml | 13 ++ .../main/res/drawable/ic_exclamation_24dp.xml | 2 +- .../drawable/ic_filter_list_black_24dp.xml | 5 - app/src/main/res/layout/fragment_grades.xml | 187 ++++++++++++++---- .../{grade_dialog.xml => grades_dialog.xml} | 0 .../{grade_header.xml => grades_header.xml} | 4 +- .../{grade_subitem.xml => grades_subitem.xml} | 0 .../main/res/layout/grades_summary_header.xml | 34 ++++ .../res/layout/grades_summary_subitem.xml | 75 +++++++ app/src/main/res/menu/grades_action_menu.xml | 20 ++ app/src/main/res/menu/semester_switch.xml | 13 -- app/src/main/res/values-pl/strings.xml | 9 + app/src/main/res/values/strings.xml | 9 + .../wulkanowy/utils/GradeUtilsTest.java | 57 ++++-- 40 files changed, 791 insertions(+), 178 deletions(-) rename app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/{AttendanceHeaderItem.java => AttendanceHeader.java} (95%) rename app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/{ExamsHeaderItem.java => ExamsHeader.java} (92%) rename app/src/main/java/io/github/wulkanowy/ui/main/grades/{GradeHeaderItem.java => GradesHeader.java} (94%) create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSummaryHeader.java create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSummarySubItem.java rename app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/{TimetableHeaderItem.java => TimetableHeader.java} (95%) create mode 100644 app/src/main/res/drawable/ic_action_menu_semester.xml create mode 100644 app/src/main/res/drawable/ic_action_menu_summary.xml delete mode 100644 app/src/main/res/drawable/ic_filter_list_black_24dp.xml rename app/src/main/res/layout/{grade_dialog.xml => grades_dialog.xml} (100%) rename app/src/main/res/layout/{grade_header.xml => grades_header.xml} (97%) rename app/src/main/res/layout/{grade_subitem.xml => grades_subitem.xml} (100%) create mode 100644 app/src/main/res/layout/grades_summary_header.xml create mode 100644 app/src/main/res/layout/grades_summary_subitem.xml create mode 100644 app/src/main/res/menu/grades_action_menu.xml delete mode 100644 app/src/main/res/menu/semester_switch.xml diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceHeaderItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceHeader.java similarity index 95% rename from app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceHeaderItem.java rename to app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceHeader.java index 1c55f40c0..940d1fd29 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceHeaderItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceHeader.java @@ -24,12 +24,12 @@ import eu.davidea.viewholders.ExpandableViewHolder; import io.github.wulkanowy.R; import io.github.wulkanowy.data.db.dao.entities.Day; -public class AttendanceHeaderItem - extends AbstractExpandableHeaderItem { +public class AttendanceHeader + extends AbstractExpandableHeaderItem { private Day day; - AttendanceHeaderItem(Day day) { + AttendanceHeader(Day day) { this.day = day; } @@ -39,7 +39,7 @@ public class AttendanceHeaderItem if (o == null || getClass() != o.getClass()) return false; - AttendanceHeaderItem that = (AttendanceHeaderItem) o; + AttendanceHeader that = (AttendanceHeader) o; return new EqualsBuilder() .append(day, that.day) diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceSubItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceSubItem.java index 6b6246d25..65c8329ef 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceSubItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceSubItem.java @@ -23,11 +23,11 @@ import io.github.wulkanowy.data.db.dao.entities.AttendanceLesson; import io.github.wulkanowy.ui.main.attendance.AttendanceDialogFragment; class AttendanceSubItem - extends AbstractSectionableItem { + extends AbstractSectionableItem { private AttendanceLesson lesson; - AttendanceSubItem(AttendanceHeaderItem header, AttendanceLesson lesson) { + AttendanceSubItem(AttendanceHeader header, AttendanceLesson lesson) { super(header); this.lesson = lesson; } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabContract.java index d7c459042..a83e67e86 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabContract.java @@ -8,7 +8,7 @@ public interface AttendanceTabContract { interface View extends BaseContract.View { - void updateAdapterList(List headerItems); + void updateAdapterList(List headerItems); void onRefreshSuccess(); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabFragment.java index 7b5ad1cec..8de474690 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabFragment.java @@ -40,7 +40,7 @@ public class AttendanceTabFragment extends BaseFragment implements AttendanceTab AttendanceTabContract.Presenter presenter; @Inject - FlexibleAdapter adapter; + FlexibleAdapter adapter; private boolean isFragmentVisible = false; @@ -83,7 +83,7 @@ public class AttendanceTabFragment extends BaseFragment implements AttendanceTab } @Override - public void updateAdapterList(List headerItems) { + public void updateAdapterList(List headerItems) { adapter.updateDataSet(headerItems); } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabModule.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabModule.java index 01bb9aa40..380a221f2 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabModule.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabModule.java @@ -15,7 +15,7 @@ public abstract class AttendanceTabModule { @PerChildFragment @Provides - static FlexibleAdapter provideAdapter() { + static FlexibleAdapter provideAdapter() { return new FlexibleAdapter<>(null); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabPresenter.java index 787b6eb9d..7d0c26e5a 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/attendance/tab/AttendanceTabPresenter.java @@ -24,7 +24,7 @@ public class AttendanceTabPresenter extends BasePresenter headerItems = new ArrayList<>(); + private List headerItems = new ArrayList<>(); private String date; @@ -115,7 +115,7 @@ public class AttendanceTabPresenter extends BasePresenter { +public class ExamsHeader extends AbstractHeaderItem { private Day day; - ExamsHeaderItem(Day day) { + ExamsHeader(Day day) { this.day = day; } @@ -32,7 +32,7 @@ public class ExamsHeaderItem extends AbstractHeaderItem { + extends AbstractSectionableItem { private Exam exam; - ExamsSubItem(ExamsHeaderItem header, Exam exam) { + ExamsSubItem(ExamsHeader header, Exam exam) { super(header); this.exam = exam; } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabPresenter.java index 062c0fd83..b60a4607b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exams/tab/ExamsTabPresenter.java @@ -116,7 +116,7 @@ public class ExamsTabPresenter extends BasePresenter for (Day day : dayList) { day.resetExams(); - ExamsHeaderItem headerItem = new ExamsHeaderItem(day); + ExamsHeader headerItem = new ExamsHeader(day); List examList = day.getExams(); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesContract.java index 5583f98c9..d2423ec8d 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesContract.java @@ -12,7 +12,9 @@ public interface GradesContract { interface View extends BaseContract.View, SwipeRefreshLayout.OnRefreshListener { - void updateAdapterList(List headerItems); + void updateAdapterList(List headerItems); + + void updateSummaryAdapterList(List summarySubItems); void showNoItem(boolean show); @@ -28,6 +30,8 @@ public interface GradesContract { boolean isMenuVisible(); + void setSummaryAverages(String calculatedValue, String predictedValue, String finalValue ); + } interface Presenter extends BaseContract.Presenter { diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesDialogFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesDialogFragment.java index b8da5a969..17ebc6e61 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesDialogFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesDialogFragment.java @@ -71,7 +71,7 @@ public class GradesDialogFragment extends DialogFragment { @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.grade_dialog, container, false); + View view = inflater.inflate(R.layout.grades_dialog, container, false); ButterKnife.bind(this, view); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java index 09c0a1bbc..0d43b6833 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java @@ -13,6 +13,7 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.widget.TextView; import java.util.List; @@ -27,17 +28,38 @@ import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; public class GradesFragment extends BaseFragment implements GradesContract.View { + @BindView(R.id.grade_fragment_summary_container) + View summary; + + @BindView(R.id.grade_fragment_details_container) + View details; + @BindView(R.id.grade_fragment_recycler) RecyclerView recyclerView; + @BindView(R.id.grade_fragment_summary_recycler) + RecyclerView summaryRecyclerView; + @BindView(R.id.grade_fragment_no_item_container) View noItemView; @BindView(R.id.grade_fragment_swipe_refresh) SwipeRefreshLayout refreshLayout; + @BindView(R.id.grade_fragment_summary_predicted_average) + TextView predictedAverage; + + @BindView(R.id.grade_fragment_summary_calculated_average) + TextView calculatedAverage; + + @BindView(R.id.grade_fragment_summary_final_average) + TextView finalAverage; + @Inject - FlexibleAdapter adapter; + FlexibleAdapter adapter; + + @Inject + FlexibleAdapter summaryAdapter; @Inject GradesContract.Presenter presenter; @@ -66,43 +88,57 @@ public class GradesFragment extends BaseFragment implements GradesContract.View @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - inflater.inflate(R.menu.semester_switch, menu); + inflater.inflate(R.menu.grades_action_menu, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == R.id.action_filter) { - presenter.onSemesterSwitchActive(); - CharSequence[] items = new CharSequence[]{ - getResources().getString(R.string.semester_text, 1), - getResources().getString(R.string.semester_text, 2), - }; - new AlertDialog.Builder(getContext()) - .setTitle(R.string.switch_semester) - .setNegativeButton(R.string.cancel, null) - .setSingleChoiceItems(items, this.currentSemester, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - presenter.onSemesterChange(which); - dialog.cancel(); - } - }).show(); - return true; - } else { - return super.onOptionsItemSelected(item); + switch (item.getItemId()) { + case R.id.action_semester_switch: + presenter.onSemesterSwitchActive(); + CharSequence[] items = new CharSequence[]{ + getResources().getString(R.string.semester_text, 1), + getResources().getString(R.string.semester_text, 2), + }; + new AlertDialog.Builder(getContext()) + .setTitle(R.string.switch_semester) + .setNegativeButton(R.string.cancel, null) + .setSingleChoiceItems(items, this.currentSemester, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + presenter.onSemesterChange(which); + dialog.cancel(); + } + }).show(); + return true; + case R.id.action_summary_switch: + boolean isDetailsVisible = details.getVisibility() == View.VISIBLE; + + item.setTitle(isDetailsVisible ? R.string.action_title_details : R.string.action_title_summary); + details.setVisibility(isDetailsVisible ? View.INVISIBLE : View.VISIBLE); + summary.setVisibility(isDetailsVisible ? View.VISIBLE : View.INVISIBLE); + return true; + default: + return super.onOptionsItemSelected(item); } } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { noItemView.setVisibility(View.GONE); + summary.setVisibility(View.INVISIBLE); + details.setVisibility(View.VISIBLE); adapter.setAutoCollapseOnExpand(true); adapter.setAutoScrollOnExpand(true); adapter.expandItemsAtStartUp(); + summaryAdapter.setDisplayHeadersAtStartUp(true); recyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(view.getContext())); recyclerView.setAdapter(adapter); + summaryRecyclerView.setLayoutManager(new SmoothScrollLinearLayoutManager(view.getContext())); + summaryRecyclerView.setAdapter(summaryAdapter); + summaryRecyclerView.setNestedScrollingEnabled(false); refreshLayout.setColorSchemeResources(android.R.color.black); refreshLayout.setOnRefreshListener(this); @@ -116,6 +152,13 @@ public class GradesFragment extends BaseFragment implements GradesContract.View } } + @Override + public void setSummaryAverages(String calculatedValue, String predictedValue, String finalValue) { + calculatedAverage.setText(calculatedValue); + predictedAverage.setText(predictedValue); + finalAverage.setText(finalValue); + } + @Override public void setActivityTitle() { setTitle(getString(R.string.grades_text)); @@ -141,10 +184,15 @@ public class GradesFragment extends BaseFragment implements GradesContract.View } @Override - public void updateAdapterList(List headerItems) { + public void updateAdapterList(List headerItems) { adapter.updateDataSet(headerItems); } + @Override + public void updateSummaryAdapterList(List summarySubItems) { + summaryAdapter.updateDataSet(summarySubItems); + } + @Override public void onRefreshSuccessNoGrade() { showMessage(R.string.snackbar_no_grades); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradeHeaderItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesHeader.java similarity index 94% rename from app/src/main/java/io/github/wulkanowy/ui/main/grades/GradeHeaderItem.java rename to app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesHeader.java index 33e961898..c39fcc4d3 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradeHeaderItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesHeader.java @@ -20,14 +20,14 @@ import io.github.wulkanowy.data.db.dao.entities.Subject; import io.github.wulkanowy.utils.AnimationUtils; import io.github.wulkanowy.utils.GradeUtils; -public class GradeHeaderItem - extends AbstractExpandableHeaderItem { +public class GradesHeader + extends AbstractExpandableHeaderItem { private Subject subject; private final boolean isShowSummary; - GradeHeaderItem(Subject subject, boolean isShowSummary) { + GradesHeader(Subject subject, boolean isShowSummary) { this.subject = subject; this.isShowSummary = isShowSummary; } @@ -38,7 +38,7 @@ public class GradeHeaderItem if (o == null || getClass() != o.getClass()) return false; - GradeHeaderItem that = (GradeHeaderItem) o; + GradesHeader that = (GradesHeader) o; return new EqualsBuilder() .append(subject, that.subject) @@ -54,7 +54,7 @@ public class GradeHeaderItem @Override public int getLayoutRes() { - return R.layout.grade_header; + return R.layout.grades_header; } @Override @@ -126,7 +126,7 @@ public class GradeHeaderItem } private String getGradesAverageString() { - float average = GradeUtils.calculate(item.getGradeList()); + float average = GradeUtils.calculateWeightedAverage(item.getGradeList()); if (average < 0) { return resources.getString(R.string.info_no_average); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesModule.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesModule.java index edf00d3b8..25eeef484 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesModule.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesModule.java @@ -12,7 +12,12 @@ public abstract class GradesModule { abstract GradesContract.Presenter provideGradesPresenter(GradesPresenter gradesPresenter); @Provides - static FlexibleAdapter provideGradesAdapter() { + static FlexibleAdapter provideGradesAdapter() { + return new FlexibleAdapter<>(null); + } + + @Provides + static FlexibleAdapter provideGradesSummaryAdapter() { return new FlexibleAdapter<>(null); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java index ee6e0cb36..0f4d363cb 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesPresenter.java @@ -9,6 +9,7 @@ import org.threeten.bp.LocalDate; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import javax.inject.Inject; @@ -18,6 +19,7 @@ import io.github.wulkanowy.data.db.dao.entities.Subject; import io.github.wulkanowy.ui.base.BasePresenter; import io.github.wulkanowy.ui.main.OnFragmentIsReadyListener; import io.github.wulkanowy.utils.FabricUtils; +import io.github.wulkanowy.utils.GradeUtils; import io.github.wulkanowy.utils.async.AbstractTask; import io.github.wulkanowy.utils.async.AsyncListeners; @@ -31,12 +33,20 @@ public class GradesPresenter extends BasePresenter private OnFragmentIsReadyListener listener; - private List headerItems = new ArrayList<>(); + private List headerItems = new ArrayList<>(); + + private List summarySubItems = new ArrayList<>(); private boolean isFirstSight = false; private int semesterName; + private float finalAverage; + + private float predictedAverage; + + private float calculatedAverage; + @Inject GradesPresenter(RepositoryContract repository) { super(repository); @@ -56,7 +66,6 @@ public class GradesPresenter extends BasePresenter if (!isFirstSight) { isFirstSight = true; - reloadGrades(); } } @@ -76,12 +85,6 @@ public class GradesPresenter extends BasePresenter .putCustomAttribute("Name", semesterName)); } - private void reloadGrades() { - loadingTask = new AbstractTask(); - loadingTask.setOnFirstLoadingListener(this); - loadingTask.execute(); - } - @Override public void onFragmentVisible(boolean isVisible) { if (isVisible) { @@ -140,13 +143,17 @@ public class GradesPresenter extends BasePresenter boolean isShowSummary = getRepository().getSharedRepo().isShowGradesSummary(); headerItems = new ArrayList<>(); + summarySubItems = new ArrayList<>(); for (Subject subject : subjectList) { subject.resetGradeList(); List gradeList = subject.getGradeList(); + GradesSummaryHeader summaryHeader = new GradesSummaryHeader(subject, GradeUtils.calculateWeightedAverage(gradeList)); + summarySubItems.add(new GradesSummarySubItem(summaryHeader, subject)); + if (!gradeList.isEmpty()) { - GradeHeaderItem headerItem = new GradeHeaderItem(subject, isShowSummary); + GradesHeader headerItem = new GradesHeader(subject, isShowSummary); List subItems = new ArrayList<>(); @@ -159,6 +166,10 @@ public class GradesPresenter extends BasePresenter headerItems.add(headerItem); } } + + finalAverage = GradeUtils.calculateSubjectsAverage(subjectList, false); + predictedAverage = GradeUtils.calculateSubjectsAverage(subjectList, true); + calculatedAverage = GradeUtils.calculateDetailedSubjectsAverage(subjectList); } @Override @@ -170,9 +181,35 @@ public class GradesPresenter extends BasePresenter public void onEndLoadingAsync(boolean result, Exception exception) { getView().showNoItem(headerItems.isEmpty()); getView().updateAdapterList(headerItems); + + setSummaryAverages(); + getView().updateSummaryAdapterList(summarySubItems); + listener.onFragmentIsReady(); } + private void setSummaryAverages() { + getView().setSummaryAverages( + getFormattedAverage(calculatedAverage), + getFormattedAverage(predictedAverage), + getFormattedAverage(finalAverage) + ); + } + + private String getFormattedAverage(float average) { + if (-1.0f == average) { + return "-- --"; + } + + return String.format(Locale.FRANCE, "%.2f", average); + } + + private void reloadGrades() { + loadingTask = new AbstractTask(); + loadingTask.setOnFirstLoadingListener(this); + loadingTask.execute(); + } + private void cancelAsyncTasks() { if (refreshTask != null) { refreshTask.cancel(true); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSubItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSubItem.java index de9c54c6c..82b338aed 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSubItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSubItem.java @@ -21,7 +21,7 @@ import io.github.wulkanowy.data.db.dao.entities.Grade; import io.github.wulkanowy.utils.GradeUtils; public class GradesSubItem - extends AbstractSectionableItem { + extends AbstractSectionableItem { private Grade grade; @@ -29,7 +29,7 @@ public class GradesSubItem private View subjectAlertImage; - GradesSubItem(GradeHeaderItem header, Grade grade) { + GradesSubItem(GradesHeader header, Grade grade) { super(header); this.grade = grade; } @@ -64,7 +64,7 @@ public class GradesSubItem @Override public int getLayoutRes() { - return R.layout.grade_subitem; + return R.layout.grades_subitem; } @Override diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSummaryHeader.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSummaryHeader.java new file mode 100644 index 000000000..a06fa0d55 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSummaryHeader.java @@ -0,0 +1,87 @@ +package io.github.wulkanowy.ui.main.grades; + +import android.view.View; +import android.widget.TextView; + +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; + +import java.util.List; +import java.util.Locale; + +import butterknife.BindView; +import butterknife.ButterKnife; +import eu.davidea.flexibleadapter.FlexibleAdapter; +import eu.davidea.flexibleadapter.items.AbstractHeaderItem; +import eu.davidea.flexibleadapter.items.IFlexible; +import eu.davidea.viewholders.FlexibleViewHolder; +import io.github.wulkanowy.R; +import io.github.wulkanowy.data.db.dao.entities.Subject; + +class GradesSummaryHeader extends AbstractHeaderItem { + + private Subject subject; + + private String average; + + GradesSummaryHeader(Subject subject, float average) { + this.subject = subject; + this.average = String.format(Locale.FRANCE, "%.2f", average); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + + if (o == null || getClass() != o.getClass()) return false; + + GradesSummaryHeader that = (GradesSummaryHeader) o; + + return new EqualsBuilder() + .append(subject, that.subject) + .append(average, that.average) + .isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder(17, 37) + .append(subject) + .append(average) + .toHashCode(); + } + + @Override + public int getLayoutRes() { + return R.layout.grades_summary_header; + } + + @Override + public HeaderViewHolder createViewHolder(View view, FlexibleAdapter adapter) { + return new HeaderViewHolder(view, adapter); + } + + @Override + public void bindViewHolder(FlexibleAdapter adapter, HeaderViewHolder holder, int position, List payloads) { + holder.onBind(subject, average); + } + + static class HeaderViewHolder extends FlexibleViewHolder { + + @BindView(R.id.grades_summary_header_name) + TextView name; + + @BindView(R.id.grades_summary_header_average) + TextView average; + + HeaderViewHolder(View view, FlexibleAdapter adapter) { + super(view, adapter); + ButterKnife.bind(this, view); + } + + void onBind(Subject item, String value) { + name.setText(item.getName()); + average.setText("-1,00".equals(value) ? "" : value); + } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSummarySubItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSummarySubItem.java new file mode 100644 index 000000000..8ca9e484b --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesSummarySubItem.java @@ -0,0 +1,83 @@ +package io.github.wulkanowy.ui.main.grades; + +import android.view.View; +import android.widget.TextView; + +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; + +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import eu.davidea.flexibleadapter.FlexibleAdapter; +import eu.davidea.flexibleadapter.items.AbstractSectionableItem; +import eu.davidea.flexibleadapter.items.IFlexible; +import eu.davidea.viewholders.FlexibleViewHolder; +import io.github.wulkanowy.R; +import io.github.wulkanowy.data.db.dao.entities.Subject; + +public class GradesSummarySubItem + extends AbstractSectionableItem { + + private Subject subject; + + public GradesSummarySubItem(GradesSummaryHeader header, Subject subject) { + super(header); + this.subject = subject; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + + if (o == null || getClass() != o.getClass()) return false; + + GradesSummarySubItem that = (GradesSummarySubItem) o; + + return new EqualsBuilder() + .append(subject, that.subject) + .isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder(17, 37) + .append(subject) + .toHashCode(); + } + + @Override + public int getLayoutRes() { + return R.layout.grades_summary_subitem; + } + + @Override + public SubItemViewHolder createViewHolder(View view, FlexibleAdapter adapter) { + return new SubItemViewHolder(view, adapter); + } + + @Override + public void bindViewHolder(FlexibleAdapter adapter, SubItemViewHolder holder, int position, List payloads) { + holder.onBind(subject); + } + + static class SubItemViewHolder extends FlexibleViewHolder { + + @BindView(R.id.grades_summary_subitem_final_grade) + TextView finalGrade; + + @BindView(R.id.grades_summary_subitem_predicted_grade) + TextView predictedGrade; + + SubItemViewHolder(View view, FlexibleAdapter adapter) { + super(view, adapter); + ButterKnife.bind(this, view); + } + + void onBind(Subject item) { + predictedGrade.setText(item.getPredictedRating()); + finalGrade.setText(item.getFinalRating()); + } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeaderItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeader.java similarity index 95% rename from app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeaderItem.java rename to app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeader.java index 7e932f784..93fab8220 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeaderItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeader.java @@ -24,12 +24,12 @@ import eu.davidea.viewholders.ExpandableViewHolder; import io.github.wulkanowy.R; import io.github.wulkanowy.data.db.dao.entities.Day; -public class TimetableHeaderItem - extends AbstractExpandableHeaderItem { +public class TimetableHeader + extends AbstractExpandableHeaderItem { private Day day; - TimetableHeaderItem(Day day) { + TimetableHeader(Day day) { this.day = day; } @@ -39,7 +39,7 @@ public class TimetableHeaderItem if (o == null || getClass() != o.getClass()) return false; - TimetableHeaderItem that = (TimetableHeaderItem) o; + TimetableHeader that = (TimetableHeader) o; return new EqualsBuilder() .append(day, that.day) diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableSubItem.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableSubItem.java index 4d64b54b2..2bf47b335 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableSubItem.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableSubItem.java @@ -25,11 +25,11 @@ import io.github.wulkanowy.ui.main.timetable.TimetableDialogFragment; public class TimetableSubItem - extends AbstractSectionableItem { + extends AbstractSectionableItem { private TimetableLesson lesson; - TimetableSubItem(TimetableHeaderItem header, TimetableLesson lesson) { + TimetableSubItem(TimetableHeader header, TimetableLesson lesson) { super(header); this.lesson = lesson; } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabContract.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabContract.java index 254060a2e..0814ff3c9 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabContract.java @@ -8,7 +8,7 @@ public interface TimetableTabContract { interface View extends BaseContract.View { - void updateAdapterList(List headerItems); + void updateAdapterList(List headerItems); void expandItem(int item); diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabFragment.java index e0a30e8d3..87db51951 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabFragment.java @@ -44,7 +44,7 @@ public class TimetableTabFragment extends BaseFragment implements TimetableTabCo TimetableTabContract.Presenter presenter; @Inject - FlexibleAdapter adapter; + FlexibleAdapter adapter; private boolean isFragmentVisible = false; @@ -86,7 +86,7 @@ public class TimetableTabFragment extends BaseFragment implements TimetableTabCo } @Override - public void updateAdapterList(List headerItems) { + public void updateAdapterList(List headerItems) { adapter.updateDataSet(headerItems); } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabModule.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabModule.java index 3e1645f31..1afb055ff 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabModule.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabModule.java @@ -15,7 +15,7 @@ public abstract class TimetableTabModule { @PerChildFragment @Provides - static FlexibleAdapter provideTimetableAdapter() { + static FlexibleAdapter provideTimetableAdapter() { return new FlexibleAdapter<>(null); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabPresenter.java index 8841a7506..42f2424d1 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableTabPresenter.java @@ -28,7 +28,7 @@ public class TimetableTabPresenter extends BasePresenter headerItems = new ArrayList<>(); + private List headerItems = new ArrayList<>(); private String date; @@ -117,7 +117,7 @@ public class TimetableTabPresenter extends BasePresenter gradeList) { + public static float calculateWeightedAverage(List gradeList) { float counter = 0f; float denominator = 0f; for (Grade grade : gradeList) { - int integerWeight = getIntegerForWeightOfGrade(grade.getWeight()); - float floatValue = getMathematicalValueOfGrade(grade.getValue()); + int weight = getWeightValue(grade.getWeight()); + float value = getWeightedGradeValue(grade.getValue()); - if (floatValue != -1f) { - counter += floatValue * integerWeight; - denominator += integerWeight; + if (value != -1.0f) { + counter += value * weight; + denominator += weight; } } if (counter == 0f) { - return -1f; - } else { - return counter / denominator; + return -1.0f; } + 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.33f; - } else if (valueOfGrade.matches("[+][0-6]") - || valueOfGrade.matches("[0-6][+]")) { - String replacedValue = valueOfGrade.replaceAll("[+]", ""); - return Float.valueOf((replacedValue)) + 0.33f; - } 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; - } + public static float calculateSubjectsAverage(List subjectList, boolean usePredicted) { + return calculateSubjectsAverage(subjectList, usePredicted, false); } - private static int getIntegerForWeightOfGrade(String weightOfGrade) { - return Integer.valueOf(weightOfGrade.substring(0, weightOfGrade.length() - 3)); + public static float calculateDetailedSubjectsAverage(List subjectList) { + return calculateSubjectsAverage(subjectList, false, true); } public static int getValueColor(String value) { @@ -93,4 +74,80 @@ public final class GradeUtils { return R.color.default_grade; } } + + private static float calculateSubjectsAverage(List subjectList, boolean usePredicted, boolean useSubjectsAverages) { + float counter = 0f; + float denominator = 0f; + + for (Subject subject : subjectList) { + float value; + + if (useSubjectsAverages) { + value = calculateWeightedAverage(subject.getGradeList()); + } else { + value = getGradeValue(usePredicted ? subject.getPredictedRating() : subject.getFinalRating()); + } + + if (value != -1.0f) { + counter += Math.round(value); + denominator++; + } + } + + if (counter == 0) { + return -1.0f; + } + + return counter / denominator; + } + + private static float getGradeValue(String grade) { + if (validGradePattern.matcher(grade).matches()) { + return getWeightedGradeValue(grade); + } + + return getVerbalGradeValue(grade); + } + + private static float getVerbalGradeValue(String grade) { + switch (grade) { + case "celujący": + return 6f; + case "bardzo dobry": + return 5f; + case "dobry": + return 4f; + case "dostateczny": + return 3f; + case "dopuszczający": + return 2f; + case "niedostateczny": + return 1f; + default: + return -1f; + } + } + + private static float getWeightedGradeValue(String value) { + if (validGradePattern.matcher(value).matches()) { + if (value.matches("[-][0-6]") || value.matches("[0-6][-]")) { + String replacedValue = value.replaceAll("[-]", ""); + return Float.valueOf(replacedValue) - 0.33f; + } else if (value.matches("[+][0-6]") || value.matches("[0-6][+]")) { + String replacedValue = value.replaceAll("[+]", ""); + return Float.valueOf((replacedValue)) + 0.33f; + } else if (value.matches("[-|=]{1,2}[0-6]") || value.matches("[0-6][-|=]{1,2}")) { + String replacedValue = value.replaceAll("[-|=]{1,2}", ""); + return Float.valueOf((replacedValue)) - 0.5f; + } else { + return Float.valueOf(value); + } + } else { + return -1; + } + } + + private static int getWeightValue(String weightOfGrade) { + return Integer.valueOf(weightOfGrade.substring(0, weightOfGrade.length() - 3)); + } } diff --git a/app/src/main/res/drawable/ic_action_menu_semester.xml b/app/src/main/res/drawable/ic_action_menu_semester.xml new file mode 100644 index 000000000..b7acb9df9 --- /dev/null +++ b/app/src/main/res/drawable/ic_action_menu_semester.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_action_menu_summary.xml b/app/src/main/res/drawable/ic_action_menu_summary.xml new file mode 100644 index 000000000..1b2a93b8c --- /dev/null +++ b/app/src/main/res/drawable/ic_action_menu_summary.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_exclamation_24dp.xml b/app/src/main/res/drawable/ic_exclamation_24dp.xml index 4d3c91cfb..149504585 100644 --- a/app/src/main/res/drawable/ic_exclamation_24dp.xml +++ b/app/src/main/res/drawable/ic_exclamation_24dp.xml @@ -1,4 +1,4 @@ - + - - diff --git a/app/src/main/res/layout/fragment_grades.xml b/app/src/main/res/layout/fragment_grades.xml index f00b3108c..f0642987a 100644 --- a/app/src/main/res/layout/fragment_grades.xml +++ b/app/src/main/res/layout/fragment_grades.xml @@ -6,45 +6,166 @@ android:layout_height="match_parent" tools:context="io.github.wulkanowy.ui.main.grades.GradesFragment"> - - - - - - - - + android:layout_height="match_parent"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - \ No newline at end of file diff --git a/app/src/main/res/layout/grade_dialog.xml b/app/src/main/res/layout/grades_dialog.xml similarity index 100% rename from app/src/main/res/layout/grade_dialog.xml rename to app/src/main/res/layout/grades_dialog.xml diff --git a/app/src/main/res/layout/grade_header.xml b/app/src/main/res/layout/grades_header.xml similarity index 97% rename from app/src/main/res/layout/grade_header.xml rename to app/src/main/res/layout/grades_header.xml index 032ad6755..41b98076b 100644 --- a/app/src/main/res/layout/grade_header.xml +++ b/app/src/main/res/layout/grades_header.xml @@ -51,6 +51,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/grade_header_average_text" + android:layout_marginEnd="10dp" + android:layout_marginRight="10dp" android:layout_marginTop="5dp" android:text="@string/info_grades_predicted_rating" android:textColor="@color/secondary_text" @@ -61,8 +63,6 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/grade_header_average_text" - android:layout_marginLeft="10dp" - android:layout_marginStart="10dp" android:layout_marginTop="5dp" android:layout_toEndOf="@+id/grade_header_predicted_rating_text" android:layout_toRightOf="@+id/grade_header_predicted_rating_text" diff --git a/app/src/main/res/layout/grade_subitem.xml b/app/src/main/res/layout/grades_subitem.xml similarity index 100% rename from app/src/main/res/layout/grade_subitem.xml rename to app/src/main/res/layout/grades_subitem.xml diff --git a/app/src/main/res/layout/grades_summary_header.xml b/app/src/main/res/layout/grades_summary_header.xml new file mode 100644 index 000000000..3055721f9 --- /dev/null +++ b/app/src/main/res/layout/grades_summary_header.xml @@ -0,0 +1,34 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/grades_summary_subitem.xml b/app/src/main/res/layout/grades_summary_subitem.xml new file mode 100644 index 000000000..c7715092c --- /dev/null +++ b/app/src/main/res/layout/grades_summary_subitem.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/menu/grades_action_menu.xml b/app/src/main/res/menu/grades_action_menu.xml new file mode 100644 index 000000000..0533ae39e --- /dev/null +++ b/app/src/main/res/menu/grades_action_menu.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/app/src/main/res/menu/semester_switch.xml b/app/src/main/res/menu/semester_switch.xml deleted file mode 100644 index 6f8a027e3..000000000 --- a/app/src/main/res/menu/semester_switch.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index aeb828d1a..715e8adaa 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -81,6 +81,9 @@ Brak lekcji w tym tygodniu Sala %s + Przewidywana + Końcowa + %d ocena %d oceny @@ -154,4 +157,10 @@ Brak sprawdzianów w tym tygodniu Typ Data wpisu + + Obliczona średnia + Szacowana średnia + Końcowa średnia + Podsumowanie + Szczegóły diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1ffea541e..d7cf1806d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -80,6 +80,9 @@ Final: %1$s No lesson in this week + Predicted + Final + Room %s @@ -149,4 +152,10 @@ No exams in this week Type Date of entry + + Calculated average + Predicted average + Final average + Summary + Details diff --git a/app/src/test/java/io/github/wulkanowy/utils/GradeUtilsTest.java b/app/src/test/java/io/github/wulkanowy/utils/GradeUtilsTest.java index 92a0b42cf..1a5f9e4aa 100644 --- a/app/src/test/java/io/github/wulkanowy/utils/GradeUtilsTest.java +++ b/app/src/test/java/io/github/wulkanowy/utils/GradeUtilsTest.java @@ -1,6 +1,5 @@ package io.github.wulkanowy.utils; -import org.junit.Assert; import org.junit.Test; import java.util.ArrayList; @@ -8,11 +7,14 @@ import java.util.List; import io.github.wulkanowy.R; import io.github.wulkanowy.data.db.dao.entities.Grade; +import io.github.wulkanowy.data.db.dao.entities.Subject; + +import static org.junit.Assert.assertEquals; public class GradeUtilsTest { @Test - public void averageTest() { + public void weightedAverageTest() { List gradeList = new ArrayList<>(); gradeList.add(new Grade().setValue("np.").setWeight("1,00")); gradeList.add(new Grade().setValue("-5").setWeight("10,00")); @@ -29,31 +31,48 @@ public class GradeUtilsTest { gradeList1.add(new Grade().setValue("5+").setWeight("10,00")); gradeList1.add(new Grade().setValue("5").setWeight("10,00")); - Assert.assertEquals(4.8f, GradeUtils.calculate(gradeList), 0.0f); - Assert.assertEquals(4.8f, GradeUtils.calculate(gradeList1), 0.0f); + assertEquals(4.8f, GradeUtils.calculateWeightedAverage(gradeList), 0.0f); + assertEquals(4.8f, GradeUtils.calculateWeightedAverage(gradeList1), 0.0f); } @Test - public void errorAverageTest() { + public void subjectsAverageTest() { + List subjectList = new ArrayList<>(); + subjectList.add(new Subject().setPredictedRating("2").setFinalRating("3")); + subjectList.add(new Subject().setPredictedRating("niedostateczny").setFinalRating("dopuszczający")); + subjectList.add(new Subject().setPredictedRating("dostateczny").setFinalRating("dobry")); + subjectList.add(new Subject().setPredictedRating("bardzo dobry").setFinalRating("celujący")); + subjectList.add(new Subject().setPredictedRating("2/3").setFinalRating("-4")); + + assertEquals(3.8f, GradeUtils.calculateSubjectsAverage(subjectList, false), 0.0f); + assertEquals(2.75f, GradeUtils.calculateSubjectsAverage(subjectList, true), 0.0f); + } + + @Test + public void abnormalAverageTest() { List gradeList = new ArrayList<>(); gradeList.add(new Grade().setValue("np.").setWeight("1,00")); - Assert.assertEquals(-1f, GradeUtils.calculate(gradeList), 0.0f); + List subjectList = new ArrayList<>(); + subjectList.add(new Subject().setFinalRating("nieklasyfikowany")); + + assertEquals(-1f, GradeUtils.calculateWeightedAverage(gradeList), 0.0f); + assertEquals(-1f, GradeUtils.calculateSubjectsAverage(subjectList, false), 0.0f); } @Test - public void getValueColor() { - Assert.assertEquals(R.color.six_grade, GradeUtils.getValueColor("-6")); - Assert.assertEquals(R.color.five_grade, GradeUtils.getValueColor("--5")); - Assert.assertEquals(R.color.four_grade, GradeUtils.getValueColor("=4")); - Assert.assertEquals(R.color.three_grade, GradeUtils.getValueColor("3-")); - Assert.assertEquals(R.color.two_grade, GradeUtils.getValueColor("2--")); - Assert.assertEquals(R.color.two_grade, GradeUtils.getValueColor("2=")); - Assert.assertEquals(R.color.one_grade, GradeUtils.getValueColor("1+")); - Assert.assertEquals(R.color.one_grade, GradeUtils.getValueColor("+1")); - Assert.assertEquals(R.color.default_grade, GradeUtils.getValueColor("6 (.XI)")); - Assert.assertEquals(R.color.default_grade, GradeUtils.getValueColor("Np")); - Assert.assertEquals(R.color.default_grade, GradeUtils.getValueColor("7")); - Assert.assertEquals(R.color.default_grade, GradeUtils.getValueColor("")); + public void getValueColorTest() { + assertEquals(R.color.six_grade, GradeUtils.getValueColor("-6")); + assertEquals(R.color.five_grade, GradeUtils.getValueColor("--5")); + assertEquals(R.color.four_grade, GradeUtils.getValueColor("=4")); + assertEquals(R.color.three_grade, GradeUtils.getValueColor("3-")); + assertEquals(R.color.two_grade, GradeUtils.getValueColor("2--")); + assertEquals(R.color.two_grade, GradeUtils.getValueColor("2=")); + assertEquals(R.color.one_grade, GradeUtils.getValueColor("1+")); + assertEquals(R.color.one_grade, GradeUtils.getValueColor("+1")); + assertEquals(R.color.default_grade, GradeUtils.getValueColor("6 (.XI)")); + assertEquals(R.color.default_grade, GradeUtils.getValueColor("Np")); + assertEquals(R.color.default_grade, GradeUtils.getValueColor("7")); + assertEquals(R.color.default_grade, GradeUtils.getValueColor("")); } } From a06d11412786cf34a8b78e9f2897cee1f50cbe6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Wed, 6 Jun 2018 19:38:54 +0200 Subject: [PATCH 009/263] Add logger (#131) --- api/build.gradle | 1 + .../java/io/github/wulkanowy/api/Client.java | 38 +++++++++++---- .../io/github/wulkanowy/api/DateTimeUtils.kt | 8 +++- .../wulkanowy/api/StudentAndParent.java | 26 +++++++--- .../java/io/github/wulkanowy/api/Vulcan.java | 9 +++- .../wulkanowy/api/mobile/RegisteredDevices.kt | 14 +----- .../wulkanowy/api/StudentAndParentTest.java | 6 +-- ...Parent.html => WitrynaUczniaIRodzica.html} | 0 app/build.gradle | 3 ++ .../io/github/wulkanowy/WulkanowyApp.java | 13 +++-- .../wulkanowy/data/db/dao/DbHelper.java | 12 ++--- .../data/db/dao/migrations/Migration23.java | 2 +- .../db/resources/ResourcesRepository.java | 7 +-- .../wulkanowy/data/sync/AccountSync.java | 17 +++---- .../wulkanowy/data/sync/AttendanceSync.java | 4 +- .../github/wulkanowy/data/sync/ExamsSync.java | 4 +- .../github/wulkanowy/data/sync/GradeSync.java | 9 ++-- .../wulkanowy/data/sync/SubjectSync.java | 4 +- .../wulkanowy/data/sync/SyncRepository.java | 21 ++++----- .../wulkanowy/data/sync/TimetableSync.java | 4 +- .../wulkanowy/services/jobs/SyncJob.java | 13 +++-- .../wulkanowy/ui/login/LoginPresenter.java | 4 +- .../ui/main/exams/ExamsFragment.java | 2 - .../wulkanowy/ui/splash/SplashActivity.java | 1 - .../github/wulkanowy/utils/FabricUtils.java | 16 +++++-- .../io/github/wulkanowy/utils/LogUtils.java | 26 ---------- .../github/wulkanowy/utils/LoggerUtils.java | 47 +++++++++++++++++++ .../wulkanowy/utils/async/AbstractTask.java | 8 ++-- .../wulkanowy/utils/security/Scrambler.java | 4 +- .../data/db/dao/entities/GradeTest.java | 2 - build.gradle | 4 ++ 31 files changed, 201 insertions(+), 128 deletions(-) rename api/src/test/resources/io/github/wulkanowy/api/{StudentAndParent.html => WitrynaUczniaIRodzica.html} (100%) delete mode 100644 app/src/main/java/io/github/wulkanowy/utils/LogUtils.java create mode 100644 app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.java diff --git a/api/build.gradle b/api/build.gradle index f247baf10..1f7cf1979 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -32,6 +32,7 @@ dependencies { implementation "org.jsoup:jsoup:$jsoup" implementation "org.apache.commons:commons-lang3:$apacheLang" implementation "com.google.code.gson:gson:$gson" + implementation "org.slf4j:slf4j-api:$slf4jApi" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" diff --git a/api/src/main/java/io/github/wulkanowy/api/Client.java b/api/src/main/java/io/github/wulkanowy/api/Client.java index 277b80393..869ed65e3 100644 --- a/api/src/main/java/io/github/wulkanowy/api/Client.java +++ b/api/src/main/java/io/github/wulkanowy/api/Client.java @@ -3,6 +3,8 @@ package io.github.wulkanowy.api; import org.jsoup.Connection; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.Date; @@ -27,6 +29,8 @@ public class Client { private Cookies cookies = new Cookies(); + private static final Logger logger = LoggerFactory.getLogger(Client.class); + Client(String email, String password, String symbol) { this.email = email; this.password = password; @@ -59,9 +63,13 @@ public class Client { } this.symbol = new Login(this).login(email, password, symbol); + logger.info("Login successful on {} at {}", getHost(), new Date()); } private boolean isLoggedIn() { + logger.debug("Last success request: {}", lastSuccessRequest); + logger.debug("Cookies: {}", getCookies().size()); + return getCookies().size() > 0 && lastSuccessRequest != null && 5 > TimeUnit.MILLISECONDS.toMinutes(new Date().getTime() - lastSuccessRequest.getTime()); @@ -75,10 +83,6 @@ public class Client { this.symbol = symbol; } - public void addCookies(Map items) { - cookies.addItems(items); - } - private Map getCookies() { return cookies.getItems(); } @@ -111,7 +115,11 @@ public class Client { this.cookies.addItems(cookies); } - Connection.Response response = Jsoup.connect(getFilledUrl(url)) + url = getFilledUrl(url); + + logger.debug("GET {}", url); + + Connection.Response response = Jsoup.connect(url) .followRedirects(true) .cookies(getCookies()) .execute(); @@ -128,7 +136,11 @@ public class Client { } public synchronized Document postPageByUrl(String url, String[][] params) throws IOException, VulcanException { - Connection connection = Jsoup.connect(getFilledUrl(url)); + url = getFilledUrl(url); + + logger.debug("POST {}", url); + + Connection connection = Jsoup.connect(url); for (String[] data : params) { connection.data(data[0], data[1]); @@ -150,7 +162,11 @@ public class Client { public String getJsonStringByUrl(String url) throws IOException, VulcanException { login(); - Connection.Response response = Jsoup.connect(getFilledUrl(url)) + url = getFilledUrl(url); + + logger.debug("GET {}", url); + + Connection.Response response = Jsoup.connect(url) .followRedirects(true) .ignoreContentType(true) .cookies(getCookies()) @@ -164,7 +180,11 @@ public class Client { public String postJsonStringByUrl(String url, String[][] params) throws IOException, VulcanException { login(); - Connection connection = Jsoup.connect(getFilledUrl(url)); + url = getFilledUrl(url); + + logger.debug("POST {}", url); + + Connection connection = Jsoup.connect(url); for (String[] data : params) { connection.data(data[0], data[1]); @@ -196,7 +216,7 @@ public class Client { } if ("Błąd strony".equals(title)) { - throw new NotLoggedInErrorException(title + " " + doc.selectFirst("p, body") + ", status: " + code); + throw new NotLoggedInErrorException(title + " " + doc.selectFirst("body") + ", status: " + code); } return doc; diff --git a/api/src/main/java/io/github/wulkanowy/api/DateTimeUtils.kt b/api/src/main/java/io/github/wulkanowy/api/DateTimeUtils.kt index bad4e97df..3b620db50 100644 --- a/api/src/main/java/io/github/wulkanowy/api/DateTimeUtils.kt +++ b/api/src/main/java/io/github/wulkanowy/api/DateTimeUtils.kt @@ -14,9 +14,13 @@ fun getFormattedDate(date: String): String { } fun getFormattedDate(date: String, format: String): String { - val sdf = SimpleDateFormat(LOG_DATE_PATTERN, Locale.ROOT) + return getFormattedDate(date, LOG_DATE_PATTERN, format) +} + +fun getFormattedDate(date: String, fromFormat: String, toFormat: String): String { + val sdf = SimpleDateFormat(fromFormat, Locale.ROOT) val d = sdf.parse(date) - sdf.applyPattern(format) + sdf.applyPattern(toFormat) return sdf.format(d) } diff --git a/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java b/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java index a4b8fefa0..03a7b0e55 100644 --- a/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java +++ b/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java @@ -3,6 +3,8 @@ package io.github.wulkanowy.api; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.URL; @@ -32,6 +34,8 @@ public class StudentAndParent implements SnP { private String diaryID; + private static final Logger logger = LoggerFactory.getLogger(StudentAndParent.class); + StudentAndParent(Client client, String schoolID, String studentID, String diaryID) { this.client = client; this.schoolID = schoolID; @@ -43,6 +47,11 @@ public class StudentAndParent implements SnP { if (null == getStudentID() || "".equals(getStudentID())) { Document doc = client.getPageByUrl(getSnpHomePageUrl()); + if (doc.select("#idSection").isEmpty()) { + logger.error("Expected SnP page, got page with title: {} {}", doc.title(), doc.selectFirst("body")); + throw new VulcanException("Nieznany błąd podczas pobierania danych. Strona: " + doc.title()); + } + Student student = getCurrent(getStudents(doc)); studentID = student.getId(); @@ -72,24 +81,27 @@ public class StudentAndParent implements SnP { // get url to uonetplus-opiekun.fakelog.cf Document startPage = client.getPageByUrl(START_PAGE_URL); - Element studentTileLink = startPage.select(".panel.linkownia.pracownik.klient > a").first(); + Elements studentTileLink = startPage.select(".panel.linkownia.pracownik.klient > a"); - if (null == studentTileLink) { + logger.debug("studentTileLink: {}", studentTileLink.size()); + + if (studentTileLink.isEmpty()) { throw new VulcanException("Na pewno używasz konta z dostępem do Witryny ucznia i rodzica?"); } - String snpPageUrl = studentTileLink.attr("href"); + String snpPageUrl = studentTileLink.last().attr("href"); this.schoolID = getExtractedIdFromUrl(snpPageUrl); return snpPageUrl; } - String getExtractedIdFromUrl(String snpPageUrl) throws NotLoggedInErrorException { + String getExtractedIdFromUrl(String snpPageUrl) throws VulcanException { String[] path = snpPageUrl.split(client.getHost())[1].split("/"); if (5 != path.length) { - throw new NotLoggedInErrorException("You are probably not logged in " + snpPageUrl); + logger.error("Expected snp url, got {}", snpPageUrl); + throw new VulcanException("Na pewno używasz konta z dostępem do Witryny ucznia i rodzica?"); } return path[2]; @@ -107,12 +119,12 @@ public class StudentAndParent implements SnP { Map cookies = new HashMap<>(); cookies.put("idBiezacyDziennik", diaryID); cookies.put("idBiezacyUczen", studentID); - client.addCookies(cookies); Document doc = client.getPageByUrl(getBaseUrl() + url, true, cookies); if (!doc.title().startsWith("Witryna ucznia i rodzica")) { - throw new VulcanException("Expected SnP page, got page with title: " + doc.title()); + logger.error("Expected SnP page, got page with title: {} {}", doc.title(), doc.selectFirst("body")); + throw new VulcanException("Nieznany błąd podczas pobierania danych. Strona: " + doc.title()); } if (doc.title().endsWith("Strona główna")) { diff --git a/api/src/main/java/io/github/wulkanowy/api/Vulcan.java b/api/src/main/java/io/github/wulkanowy/api/Vulcan.java index c8c4d2b0e..2b4d1205c 100644 --- a/api/src/main/java/io/github/wulkanowy/api/Vulcan.java +++ b/api/src/main/java/io/github/wulkanowy/api/Vulcan.java @@ -1,5 +1,8 @@ package io.github.wulkanowy.api; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.IOException; import io.github.wulkanowy.api.attendance.AttendanceStatistics; @@ -30,17 +33,21 @@ public class Vulcan { private String diaryId; + private static final Logger logger = LoggerFactory.getLogger(Vulcan.class); + public void setCredentials(String email, String password, String symbol, String schoolId, String studentId, String diaryId) { this.schoolId = schoolId; this.studentId = studentId; this.diaryId = diaryId; client = new Client(email, password, symbol); + + logger.debug("Client created with symbol " + symbol); } public Client getClient() throws NotLoggedInErrorException { if (null == client) { - throw new NotLoggedInErrorException("Use setCredentials() method first"); + throw new NotLoggedInErrorException("Vulcan must be initialized by calling setCredentials() prior to fetch data"); } return client; diff --git a/api/src/main/java/io/github/wulkanowy/api/mobile/RegisteredDevices.kt b/api/src/main/java/io/github/wulkanowy/api/mobile/RegisteredDevices.kt index cd08a5858..d622b4de3 100644 --- a/api/src/main/java/io/github/wulkanowy/api/mobile/RegisteredDevices.kt +++ b/api/src/main/java/io/github/wulkanowy/api/mobile/RegisteredDevices.kt @@ -1,8 +1,7 @@ package io.github.wulkanowy.api.mobile import io.github.wulkanowy.api.SnP -import java.text.SimpleDateFormat -import java.util.* +import io.github.wulkanowy.api.getFormattedDate class RegisteredDevices(private val snp: SnP) { @@ -28,7 +27,7 @@ class RegisteredDevices(private val snp: SnP) { devices.add(Device( cells[0].text().replace(" ($system)", ""), system, - formatDate(cells[1].text()), + getFormattedDate(cells[1].text(), "dd.MM.yyyy 'godz:' HH:mm:ss", "yyyy-MM-dd HH:mm:ss"), cells[2].select("a").attr("href") .split("/").last().toInt() )) @@ -36,13 +35,4 @@ class RegisteredDevices(private val snp: SnP) { return devices } - - // TODO: Move to date utils - private fun formatDate(date: String): String { - val sdf = SimpleDateFormat("dd.MM.yyyy 'godz:' HH:mm:ss", Locale.ROOT) - val d = sdf.parse(date) - sdf.applyPattern("yyyy-MM-dd HH:mm:ss") - - return sdf.format(d) - } } diff --git a/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java b/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java index 1b6f7a91b..ba0c8f7fb 100644 --- a/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java +++ b/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java @@ -83,7 +83,7 @@ public class StudentAndParentTest { snp.getExtractedIdFromUrl("https://uonetplus-opiekun.vulcan.net.pl/demoupowiat/demo12345/Start/Index/")); } - @Test(expected = NotLoggedInErrorException.class) + @Test(expected = VulcanException.class) public void getExtractedIDNotLoggedTest() throws Exception { Mockito.when(client.getHost()).thenReturn("vulcan.net.pl"); StudentAndParent snp = new StudentAndParent(client, "symbol", null, null); @@ -131,8 +131,8 @@ public class StudentAndParentTest { @Test public void getDiariesAndStudentTest() throws IOException, VulcanException { - Document snpHome = Jsoup.parse(FixtureHelper.getAsString( - getClass().getResourceAsStream("StudentAndParent.html"))); + String input = FixtureHelper.getAsString(getClass().getResourceAsStream("WitrynaUczniaIRodzica.html")); + Document snpHome = Jsoup.parse(input); client = Mockito.mock(Client.class); Mockito.when(client.getPageByUrl(Mockito.anyString())).thenReturn(snpHome); diff --git a/api/src/test/resources/io/github/wulkanowy/api/StudentAndParent.html b/api/src/test/resources/io/github/wulkanowy/api/WitrynaUczniaIRodzica.html similarity index 100% rename from api/src/test/resources/io/github/wulkanowy/api/StudentAndParent.html rename to api/src/test/resources/io/github/wulkanowy/api/WitrynaUczniaIRodzica.html diff --git a/app/build.gradle b/app/build.gradle index 50677a7ae..aefebcfbe 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -118,6 +118,9 @@ dependencies { implementation "com.jakewharton.threetenabp:threetenabp:$threeTenABP" implementation "com.google.android.gms:play-services-oss-licenses:$ossLicenses" + implementation "com.jakewharton.timber:timber:$timber" + implementation "at.favre.lib:slf4j-timber:$slf4jTimber" + implementation("com.crashlytics.sdk.android:crashlytics:$crashlyticsSdk@aar") { transitive = true } diff --git a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java index 5b68abbf4..d3570512a 100644 --- a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java +++ b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java @@ -12,11 +12,12 @@ import javax.inject.Inject; import dagger.android.AndroidInjector; import dagger.android.support.DaggerApplication; import eu.davidea.flexibleadapter.FlexibleAdapter; -import eu.davidea.flexibleadapter.utils.Log; import io.fabric.sdk.android.Fabric; import io.github.wulkanowy.data.RepositoryContract; import io.github.wulkanowy.di.DaggerAppComponent; -import io.github.wulkanowy.utils.LogUtils; +import io.github.wulkanowy.utils.FabricUtils; +import io.github.wulkanowy.utils.LoggerUtils; +import timber.log.Timber; public class WulkanowyApp extends DaggerApplication { @@ -39,15 +40,18 @@ public class WulkanowyApp extends DaggerApplication { if (repository.getSharedRepo().isUserLoggedIn()) { try { repository.getSyncRepo().initLastUser(); + FabricUtils.logLogin("Open app", true); } catch (Exception e) { - LogUtils.error("An error occurred when the application was started", e); + FabricUtils.logLogin("Open app", false); + Timber.e(e, "An error occurred when the application was started"); } } } private void enableDebugLog() { QueryBuilder.LOG_VALUES = true; - FlexibleAdapter.enableLogs(Log.Level.DEBUG); + FlexibleAdapter.enableLogs(eu.davidea.flexibleadapter.utils.Log.Level.DEBUG); + Timber.plant(new LoggerUtils.DebugLogTree()); } private void initializeFabric() { @@ -60,6 +64,7 @@ public class WulkanowyApp extends DaggerApplication { ) .debuggable(BuildConfig.DEBUG) .build()); + Timber.plant(new LoggerUtils.CrashlyticsTree()); } @Override diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java index 7ffcfe279..904fa3433 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java @@ -22,7 +22,7 @@ import io.github.wulkanowy.data.db.dao.migrations.Migration26; import io.github.wulkanowy.data.db.dao.migrations.Migration27; import io.github.wulkanowy.data.db.dao.migrations.Migration28; import io.github.wulkanowy.data.db.shared.SharedPrefContract; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; @Singleton public class DbHelper extends DaoMaster.OpenHelper { @@ -41,7 +41,7 @@ public class DbHelper extends DaoMaster.OpenHelper { @Override public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { - LogUtils.info("Cleaning user data oldVersion=" + oldVersion + " newVersion=" + newVersion); + Timber.i("Cleaning user data oldVersion=%s newVersion=%s", oldVersion, newVersion); Database database = new StandardDatabase(db); recreateDatabase(database); } @@ -54,11 +54,11 @@ public class DbHelper extends DaoMaster.OpenHelper { for (Migration migration : migrations) { if (oldVersion < migration.getVersion()) { try { - LogUtils.info("Applying migration to db schema v" + migration.getVersion() + "..."); + Timber.i("Applying migration to db schema v%s...", migration.getVersion()); migration.runMigration(db, sharedPref, vulcan); - LogUtils.info("Migration " + migration.getVersion() + " complete"); + Timber.i("Migration %s complete", migration.getVersion()); } catch (Exception e) { - e.printStackTrace(); + Timber.e(e, "Failed to apply migration"); recreateDatabase(db); break; } @@ -67,7 +67,7 @@ public class DbHelper extends DaoMaster.OpenHelper { } private void recreateDatabase(Database db) { - LogUtils.info("Database is recreating..."); + Timber.i("Database is recreating..."); sharedPref.setCurrentUserId(0); DaoMaster.dropAllTables(db, true); onCreate(db); diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration23.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration23.java index 97b575a02..b2a41ad15 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration23.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration23.java @@ -9,8 +9,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import io.github.wulkanowy.api.generic.Diary; import io.github.wulkanowy.api.Vulcan; +import io.github.wulkanowy.api.generic.Diary; import io.github.wulkanowy.data.db.dao.DbHelper; import io.github.wulkanowy.data.db.shared.SharedPrefContract; import io.github.wulkanowy.utils.security.Scrambler; diff --git a/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java b/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java index 81aeaee2b..f8a1baaa2 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java @@ -3,8 +3,6 @@ package io.github.wulkanowy.data.db.resources; import android.content.Context; import android.content.res.Resources; -import com.crashlytics.android.Crashlytics; - import java.io.IOException; import java.net.SocketTimeoutException; import java.net.UnknownHostException; @@ -16,8 +14,8 @@ import io.github.wulkanowy.R; import io.github.wulkanowy.api.NotLoggedInErrorException; import io.github.wulkanowy.data.db.dao.entities.AttendanceLesson; import io.github.wulkanowy.utils.AppConstant; -import io.github.wulkanowy.utils.LogUtils; import io.github.wulkanowy.utils.security.CryptoException; +import timber.log.Timber; @Singleton public class ResourcesRepository implements ResourcesContract { @@ -41,8 +39,7 @@ public class ResourcesRepository implements ResourcesContract { @Override public String getErrorLoginMessage(Exception exception) { - LogUtils.error(AppConstant.APP_NAME + " encountered a error", exception); - Crashlytics.logException(exception); + Timber.e(exception,"%s encountered a error", AppConstant.APP_NAME); if (exception instanceof CryptoException) { return resources.getString(R.string.encrypt_failed_text); diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java index 032e95e4e..b9f72cb2d 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java @@ -24,9 +24,9 @@ import io.github.wulkanowy.data.db.dao.entities.Symbol; import io.github.wulkanowy.data.db.dao.entities.SymbolDao; import io.github.wulkanowy.data.db.shared.SharedPrefContract; import io.github.wulkanowy.utils.DataObjectConverter; -import io.github.wulkanowy.utils.LogUtils; import io.github.wulkanowy.utils.security.CryptoException; import io.github.wulkanowy.utils.security.Scrambler; +import timber.log.Timber; @Singleton public class AccountSync { @@ -73,7 +73,7 @@ public class AccountSync { } private Account insertAccount(String email, String password) throws CryptoException { - LogUtils.debug("Register account: " + email); + Timber.d("Register account"); Account account = new Account() .setEmail(email) .setPassword(Scrambler.encrypt(email, password, context)); @@ -82,10 +82,11 @@ public class AccountSync { } private Symbol insertSymbol(Account account) throws VulcanException, IOException { - LogUtils.debug("Register symbol: " + vulcan.getSymbol()); + String schoolId = vulcan.getStudentAndParent().getSchoolID(); + Timber.d("Register symbol %s", vulcan.getSymbol()); Symbol symbol = new Symbol() .setUserId(account.getId()) - .setSchoolId(vulcan.getStudentAndParent().getSchoolID()) + .setSchoolId(schoolId) .setSymbol(vulcan.getSymbol()); daoSession.getSymbolDao().insert(symbol); @@ -97,7 +98,7 @@ public class AccountSync { vulcan.getStudentAndParent().getStudents(), symbol.getId() ); - LogUtils.debug("Register students: " + studentList.size()); + Timber.d("Register students %s", studentList.size()); daoSession.getStudentDao().insertInTx(studentList); } @@ -108,7 +109,7 @@ public class AccountSync { StudentDao.Properties.SymbolId.eq(symbolEntity.getId()), StudentDao.Properties.Current.eq(true) ).unique().getId()); - LogUtils.debug("Register diaries: " + diaryList.size()); + Timber.d("Register diaries %s", diaryList.size()); daoSession.getDiaryDao().insertInTx(diaryList); } @@ -118,7 +119,7 @@ public class AccountSync { daoSession.getDiaryDao().queryBuilder().where( DiaryDao.Properties.Current.eq(true) ).unique().getId()); - LogUtils.debug("Register semesters: " + semesterList.size()); + Timber.d("Register semesters %s", semesterList.size()); daoSession.getSemesterDao().insertInTx(semesterList); } @@ -130,7 +131,7 @@ public class AccountSync { throw new NotRegisteredUserException("Can't find user id in SharedPreferences"); } - LogUtils.debug("Initialization current user id=" + userId); + Timber.d("Init current user (%s)", userId); Account account = daoSession.getAccountDao().load(userId); diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/AttendanceSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/AttendanceSync.java index 9f379be60..187694189 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/AttendanceSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/AttendanceSync.java @@ -18,7 +18,7 @@ import io.github.wulkanowy.data.db.dao.entities.DayDao; import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.data.db.dao.entities.WeekDao; import io.github.wulkanowy.utils.DataObjectConverter; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; @Singleton public class AttendanceSync { @@ -47,7 +47,7 @@ public class AttendanceSync { daoSession.getAttendanceLessonDao().saveInTx(lessonList); - LogUtils.debug("Synchronization attendance lessons (amount = " + lessonList.size() + ")"); + Timber.d("Attendance synchronization complete (%s)", lessonList.size()); } private io.github.wulkanowy.api.generic.Week getWeekFromApi(String date) diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java index 85b4dac40..db4730921 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java @@ -17,7 +17,7 @@ import io.github.wulkanowy.data.db.dao.entities.ExamDao; import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.data.db.dao.entities.WeekDao; import io.github.wulkanowy.utils.DataObjectConverter; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; public class ExamsSync { @@ -45,7 +45,7 @@ public class ExamsSync { daoSession.getExamDao().saveInTx(examList); - LogUtils.debug("Synchronization exams (amount = " + examList.size() + ")"); + Timber.d("Exams synchronization complete (%s)", examList.size()); } private Week getWeekFromDb(String date) { diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/GradeSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/GradeSync.java index 0b70695de..59a71845c 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/GradeSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/GradeSync.java @@ -1,7 +1,6 @@ package io.github.wulkanowy.data.sync; import java.io.IOException; -import java.text.ParseException; import java.util.ArrayList; import java.util.List; @@ -16,7 +15,7 @@ import io.github.wulkanowy.data.db.dao.entities.Semester; import io.github.wulkanowy.data.db.dao.entities.SubjectDao; import io.github.wulkanowy.utils.DataObjectConverter; import io.github.wulkanowy.utils.EntitiesCompare; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; @Singleton public class GradeSync { @@ -33,7 +32,7 @@ public class GradeSync { this.vulcan = vulcan; } - public void sync(long semesterId) throws IOException, VulcanException, ParseException { + public void sync(long semesterId) throws IOException, VulcanException { this.semesterId = semesterId; Semester semester = daoSession.getSemesterDao().load(semesterId); @@ -44,7 +43,7 @@ public class GradeSync { daoSession.getGradeDao().deleteInTx(semester.getGradeList()); daoSession.getGradeDao().insertInTx(lastList); - LogUtils.debug("Synchronization grades (amount = " + lastList.size() + ")"); + Timber.d("Grades synchronization complete (%s)", lastList.size()); } private void resetSemesterRelations(Semester semester) { @@ -64,7 +63,7 @@ public class GradeSync { return updatedList; } - private List getComparedList(Semester semester) throws IOException, VulcanException, ParseException { + private List getComparedList(Semester semester) throws IOException, VulcanException { List gradesFromNet = DataObjectConverter.gradesToGradeEntities( vulcan.getGradesList().getAll(semester.getValue()), semesterId); diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/SubjectSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/SubjectSync.java index 163a62340..1d0300d69 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/SubjectSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/SubjectSync.java @@ -13,7 +13,7 @@ import io.github.wulkanowy.data.db.dao.entities.DaoSession; import io.github.wulkanowy.data.db.dao.entities.Semester; import io.github.wulkanowy.data.db.dao.entities.Subject; import io.github.wulkanowy.utils.DataObjectConverter; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; @Singleton public class SubjectSync { @@ -40,7 +40,7 @@ public class SubjectSync { daoSession.getSubjectDao().deleteInTx(getSubjectsFromDb()); daoSession.getSubjectDao().insertInTx(lastList); - LogUtils.debug("Synchronization subjects (amount = " + lastList.size() + ")"); + Timber.d("Subjects synchronization complete (%s)", lastList.size()); } private List getSubjectsFromNet(Semester semester) throws VulcanException, IOException { diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/SyncRepository.java b/app/src/main/java/io/github/wulkanowy/data/sync/SyncRepository.java index 6a1e4dc1f..05dd14fdb 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/SyncRepository.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/SyncRepository.java @@ -1,7 +1,6 @@ package io.github.wulkanowy.data.sync; import java.io.IOException; -import java.text.ParseException; import javax.inject.Inject; import javax.inject.Singleton; @@ -47,17 +46,17 @@ public class SyncRepository implements SyncContract { } @Override - public void initLastUser() throws IOException, CryptoException { + public void initLastUser() throws CryptoException { accountSync.initLastUser(); } @Override - public void syncGrades(int semesterName) throws VulcanException, IOException, ParseException { + public void syncGrades(int semesterName) throws VulcanException, IOException { gradeSync.sync(semesterName); } @Override - public void syncGrades() throws VulcanException, IOException, ParseException { + public void syncGrades() throws VulcanException, IOException { gradeSync.sync(database.getCurrentSemesterId()); } @@ -72,12 +71,12 @@ public class SyncRepository implements SyncContract { } @Override - public void syncAttendance() throws ParseException, IOException, VulcanException { + public void syncAttendance() throws IOException, VulcanException { attendanceSync.syncAttendance(database.getCurrentDiaryId(), null); } @Override - public void syncAttendance(long diaryId, String date) throws ParseException, IOException, VulcanException { + public void syncAttendance(long diaryId, String date) throws IOException, VulcanException { if (diaryId != 0) { attendanceSync.syncAttendance(diaryId, date); } else { @@ -86,12 +85,12 @@ public class SyncRepository implements SyncContract { } @Override - public void syncTimetable() throws VulcanException, IOException, ParseException { + public void syncTimetable() throws VulcanException, IOException { timetableSync.syncTimetable(database.getCurrentDiaryId(), null); } @Override - public void syncTimetable(long diaryId, String date) throws VulcanException, IOException, ParseException { + public void syncTimetable(long diaryId, String date) throws VulcanException, IOException { if (diaryId != 0) { timetableSync.syncTimetable(diaryId, date); } else { @@ -100,12 +99,12 @@ public class SyncRepository implements SyncContract { } @Override - public void syncExams() throws VulcanException, IOException, ParseException { + public void syncExams() throws VulcanException, IOException { examsSync.syncExams(database.getCurrentDiaryId(), null); } @Override - public void syncExams(long diaryId, String date) throws VulcanException, IOException, ParseException { + public void syncExams(long diaryId, String date) throws VulcanException, IOException { if (diaryId != 0) { examsSync.syncExams(diaryId, date); } else { @@ -114,7 +113,7 @@ public class SyncRepository implements SyncContract { } @Override - public void syncAll() throws VulcanException, IOException, ParseException { + public void syncAll() throws VulcanException, IOException { syncSubjects(); syncGrades(); syncAttendance(); diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java index 309403c88..1ea2fa488 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java @@ -20,7 +20,7 @@ import io.github.wulkanowy.data.db.dao.entities.TimetableLessonDao; import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.data.db.dao.entities.WeekDao; import io.github.wulkanowy.utils.DataObjectConverter; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; @Singleton public class TimetableSync { @@ -49,7 +49,7 @@ public class TimetableSync { daoSession.getTimetableLessonDao().saveInTx(lessonList); - LogUtils.debug("Synchronization timetable lessons (amount = " + lessonList.size() + ")"); + Timber.d("Timetable synchronization complete (%s)", lessonList.size()); } private io.github.wulkanowy.api.generic.Week getWeekFromApi(String date) diff --git a/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java b/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java index 432bdc23a..b21363910 100644 --- a/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java +++ b/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java @@ -4,7 +4,6 @@ import android.app.PendingIntent; import android.content.Context; import android.support.v4.app.NotificationCompat; -import com.crashlytics.android.Crashlytics; import com.firebase.jobdispatcher.Constraint; import com.firebase.jobdispatcher.FirebaseJobDispatcher; import com.firebase.jobdispatcher.GooglePlayDriver; @@ -27,7 +26,8 @@ import io.github.wulkanowy.data.db.dao.entities.Grade; import io.github.wulkanowy.data.sync.NotRegisteredUserException; import io.github.wulkanowy.services.notifies.GradeNotify; import io.github.wulkanowy.ui.main.MainActivity; -import io.github.wulkanowy.utils.LogUtils; +import io.github.wulkanowy.utils.FabricUtils; +import timber.log.Timber; public class SyncJob extends SimpleJobService { @@ -74,13 +74,18 @@ public class SyncJob extends SimpleJobService { if (!gradeList.isEmpty() && repository.getSharedRepo().isNotifyEnable()) { showNotification(); } + + FabricUtils.logLogin("Background", true); + return JobService.RESULT_SUCCESS; } catch (NotRegisteredUserException e) { logError(e); stop(getApplicationContext()); + return JobService.RESULT_FAIL_NORETRY; } catch (Exception e) { logError(e); + return JobService.RESULT_FAIL_RETRY; } } @@ -122,7 +127,7 @@ public class SyncJob extends SimpleJobService { } private void logError(Exception e) { - Crashlytics.logException(e); - LogUtils.error("During background synchronization an error occurred", e); + FabricUtils.logLogin("Background", false); + Timber.e(e, "During background synchronization an error occurred"); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java index fb63e6af2..3ae1ce9e7 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java @@ -85,7 +85,7 @@ public class LoginPresenter extends BasePresenter @Override public void onEndAsync(boolean success, Exception exception) { if (success) { - FabricUtils.logRegister(true, getRepository().getDbRepo().getCurrentSymbol().getSymbol()); + FabricUtils.logRegister(true, getRepository().getDbRepo().getCurrentSymbol().getSymbol(), "Success"); getView().openMainActivity(); return; } else if (exception instanceof BadCredentialsException) { @@ -95,7 +95,7 @@ public class LoginPresenter extends BasePresenter getView().setErrorSymbolRequired(); getView().showSoftInput(); } else { - FabricUtils.logRegister(false, symbol); + FabricUtils.logRegister(false, symbol, exception.getMessage()); getView().showMessage(getRepository().getResRepo().getErrorLoginMessage(exception)); } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsFragment.java index 503257982..05557b81e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsFragment.java @@ -2,7 +2,6 @@ package io.github.wulkanowy.ui.main.exams; import android.os.Bundle; import android.support.annotation.NonNull; -import android.support.design.widget.Snackbar; import android.support.design.widget.TabLayout; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; @@ -13,7 +12,6 @@ import javax.inject.Inject; import javax.inject.Named; import butterknife.BindView; -import butterknife.ButterKnife; import io.github.wulkanowy.R; import io.github.wulkanowy.ui.base.BaseFragment; import io.github.wulkanowy.ui.base.BasePagerAdapter; diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java index b90f396c5..5e4dfec1f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java @@ -4,7 +4,6 @@ import android.os.Bundle; import javax.inject.Inject; -import io.github.wulkanowy.services.jobs.SyncJob; import io.github.wulkanowy.services.notifies.NotificationService; import io.github.wulkanowy.ui.base.BaseActivity; import io.github.wulkanowy.ui.login.LoginActivity; diff --git a/app/src/main/java/io/github/wulkanowy/utils/FabricUtils.java b/app/src/main/java/io/github/wulkanowy/utils/FabricUtils.java index 38811534c..69897caa0 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/FabricUtils.java +++ b/app/src/main/java/io/github/wulkanowy/utils/FabricUtils.java @@ -2,6 +2,7 @@ package io.github.wulkanowy.utils; import com.crashlytics.android.answers.Answers; import com.crashlytics.android.answers.CustomEvent; +import com.crashlytics.android.answers.LoginEvent; import com.crashlytics.android.answers.SignUpEvent; public final class FabricUtils { @@ -10,17 +11,26 @@ public final class FabricUtils { throw new IllegalStateException("Utility class"); } - public static void logRegister(boolean result, String symbol) { + public static void logLogin(String method, boolean result) { + Answers.getInstance().logLogin(new LoginEvent() + .putMethod(method) + .putSuccess(result) + ); + } + + public static void logRegister(boolean result, String symbol, String message) { Answers.getInstance().logSignUp(new SignUpEvent() .putMethod("Login activity") .putSuccess(result) - .putCustomAttribute("symbol", symbol)); + .putCustomAttribute("symbol", symbol) + .putCustomAttribute("message", message) + ); } public static void logRefresh(String name, boolean result, String date) { Answers.getInstance().logCustom( new CustomEvent(name + " refresh") - .putCustomAttribute("Success", result ? 1 : 0) + .putCustomAttribute("Success", result ? "true" : "false") .putCustomAttribute("Date", date) ); } diff --git a/app/src/main/java/io/github/wulkanowy/utils/LogUtils.java b/app/src/main/java/io/github/wulkanowy/utils/LogUtils.java deleted file mode 100644 index f59bbf641..000000000 --- a/app/src/main/java/io/github/wulkanowy/utils/LogUtils.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.github.wulkanowy.utils; - -import android.util.Log; - -public final class LogUtils { - - private LogUtils() { - throw new IllegalStateException("Utility class"); - } - - public static void debug(String message) { - Log.d(AppConstant.APP_NAME, message); - } - - public static void error(String message, Throwable throwable) { - Log.e(AppConstant.APP_NAME, message, throwable); - } - - public static void error(String message) { - Log.e(AppConstant.APP_NAME, message); - } - - public static void info(String message) { - Log.i(AppConstant.APP_NAME, message); - } -} diff --git a/app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.java b/app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.java new file mode 100644 index 000000000..6e6c701b1 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.java @@ -0,0 +1,47 @@ +package io.github.wulkanowy.utils; + +import android.os.Build; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.util.Log; + +import com.crashlytics.android.Crashlytics; + +import timber.log.Timber; + +public final class LoggerUtils { + + public static class CrashlyticsTree extends Timber.Tree { + + @Override + protected void log(int priority, @Nullable String tag, @Nullable String message, @Nullable Throwable t) { + Crashlytics.setInt("priority", priority); + Crashlytics.setString("tag", tag); + + if (t == null) { + Crashlytics.log(message); + } else { + Crashlytics.setString("message", message); + Crashlytics.logException(t); + } + } + } + + public static class DebugLogTree extends Timber.DebugTree { + + @Override + protected void log(int priority, String tag, @NonNull String message, Throwable t) { + if ("HUAWEI".equals(Build.MANUFACTURER) || "samsung".equals(Build.MANUFACTURER)) { + if (priority == Log.VERBOSE || priority == Log.DEBUG || priority == Log.INFO) { + priority = Log.ERROR; + } + } + super.log(priority, AppConstant.APP_NAME, message, t); + } + + @Override + protected String createStackElementTag(@NonNull StackTraceElement element) { + return super.createStackElementTag(element) + " - " + element.getLineNumber(); + } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/utils/async/AbstractTask.java b/app/src/main/java/io/github/wulkanowy/utils/async/AbstractTask.java index 5106d6417..447214164 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/async/AbstractTask.java +++ b/app/src/main/java/io/github/wulkanowy/utils/async/AbstractTask.java @@ -2,7 +2,7 @@ package io.github.wulkanowy.utils.async; import android.os.AsyncTask; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; public class AbstractTask extends AsyncTask { @@ -28,7 +28,7 @@ public class AbstractTask extends AsyncTask { } else if (onRefreshListener != null) { onRefreshListener.onDoInBackgroundRefresh(); } else { - LogUtils.error("AbstractTask does not have a listener assigned"); + Timber.e("AbstractTask does not have a listener assigned"); } return true; } catch (Exception e) { @@ -45,7 +45,7 @@ public class AbstractTask extends AsyncTask { } else if (onRefreshListener != null) { onRefreshListener.onCanceledRefreshAsync(); } else { - LogUtils.error("AbstractTask does not have a listener assigned"); + Timber.e("AbstractTask does not have a listener assigned"); } } @@ -57,7 +57,7 @@ public class AbstractTask extends AsyncTask { } else if (onRefreshListener != null) { onRefreshListener.onEndRefreshAsync(result, exception); } else { - LogUtils.error("AbstractTask does not have a listener assigned"); + Timber.e("AbstractTask does not have a listener assigned"); } } } diff --git a/app/src/main/java/io/github/wulkanowy/utils/security/Scrambler.java b/app/src/main/java/io/github/wulkanowy/utils/security/Scrambler.java index dc0c409a4..8e425a894 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/security/Scrambler.java +++ b/app/src/main/java/io/github/wulkanowy/utils/security/Scrambler.java @@ -26,7 +26,7 @@ import javax.crypto.CipherInputStream; import javax.crypto.CipherOutputStream; import javax.security.auth.x500.X500Principal; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; public final class Scrambler { @@ -111,7 +111,7 @@ public final class Scrambler { throw new CryptoException("GenerateNewKey - String is empty"); } - LogUtils.debug("Key pair are create"); + Timber.d("Key pair are create"); } diff --git a/app/src/test/java/io/github/wulkanowy/data/db/dao/entities/GradeTest.java b/app/src/test/java/io/github/wulkanowy/data/db/dao/entities/GradeTest.java index 580ffdf51..f47e75e22 100644 --- a/app/src/test/java/io/github/wulkanowy/data/db/dao/entities/GradeTest.java +++ b/app/src/test/java/io/github/wulkanowy/data/db/dao/entities/GradeTest.java @@ -3,8 +3,6 @@ package io.github.wulkanowy.data.db.dao.entities; import org.junit.Assert; import org.junit.Test; -import io.github.wulkanowy.R; - public class GradeTest { @Test diff --git a/build.gradle b/build.gradle index 0f9746575..6af8545e5 100644 --- a/build.gradle +++ b/build.gradle @@ -50,6 +50,10 @@ ext { gson = "2.8.5" ossLicenses = "15.0.1" + slf4jApi = "1.7.25" + slf4jTimber = "1.0.1" + timber = "4.7.0" + debugDb = "1.0.3" sqlcipher = "3.5.9" From 8d014ab7e92eb1ccd0fd020c24aaefb2f29c568a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82?= Date: Thu, 7 Jun 2018 08:13:49 +0200 Subject: [PATCH 010/263] Fix displaying the replacements in widget (#134) --- .../wulkanowy/ui/widgets/TimetableWidgetFactory.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetFactory.java b/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetFactory.java index 2a858b909..395e1c07a 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetFactory.java +++ b/app/src/main/java/io/github/wulkanowy/ui/widgets/TimetableWidgetFactory.java @@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.widgets; import android.content.Context; import android.content.Intent; +import android.graphics.Paint; import android.view.View; import android.widget.AdapterView; import android.widget.RemoteViews; @@ -75,13 +76,21 @@ public class TimetableWidgetFactory implements RemoteViewsService.RemoteViewsFac views.setTextViewText(R.id.timetable_widget_item_room, getRoomText(position)); if (!getDescriptionText(position).isEmpty()) { + views.setViewVisibility(R.id.timetable_widget_item_description, View.VISIBLE); views.setTextViewText(R.id.timetable_widget_item_description, getDescriptionText(position)); } else { views.setViewVisibility(R.id.timetable_widget_item_description, View.GONE); } - views.setOnClickFillInIntent(R.id.timetable_widget_item_container, new Intent()); + if (lessonList.get(position).getMovedOrCanceled()) { + views.setInt(R.id.timetable_widget_item_subject, "setPaintFlags", + Paint.STRIKE_THRU_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG); + } else { + views.setInt(R.id.timetable_widget_item_subject, "setPaintFlags", + Paint.ANTI_ALIAS_FLAG); + } + views.setOnClickFillInIntent(R.id.timetable_widget_item_container, new Intent()); return views; } From 81d177c2709c138c0cf4adcb08a524ec7b0063a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Sat, 9 Jun 2018 00:59:39 +0200 Subject: [PATCH 011/263] Hide actionbar on scroll (#135) --- .../wulkanowy/ui/main/MainActivity.java | 7 +- .../ui/main/settings/AboutScreen.java | 67 ------------------- .../ui/main/settings/SettingsFragment.java | 66 ++++++++++++------ app/src/main/res/layout/activity_main.xml | 49 ++++++-------- app/src/main/res/xml/preferences.xml | 45 +++++-------- build.gradle | 6 +- 6 files changed, 93 insertions(+), 147 deletions(-) delete mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/settings/AboutScreen.java diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java b/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java index f00f57c26..3fc03fca2 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.java @@ -5,6 +5,7 @@ import android.content.Intent; import android.graphics.Color; import android.os.Bundle; import android.support.annotation.NonNull; +import android.support.design.widget.AppBarLayout; import android.support.v7.app.ActionBar; import android.support.v7.widget.Toolbar; import android.view.View; @@ -41,6 +42,9 @@ public class MainActivity extends BaseActivity implements MainContract.View, @BindView(R.id.main_activity_progress_bar) View progressBar; + @BindView(R.id.main_activity_appbar) + AppBarLayout appBar; + @Named("Main") @Inject BasePagerAdapter pagerAdapter; @@ -56,7 +60,7 @@ public class MainActivity extends BaseActivity implements MainContract.View, public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - setSupportActionBar((Toolbar) findViewById(R.id.toolbar)); + setSupportActionBar((Toolbar) findViewById(R.id.main_activity_toolbar)); injectViews(); presenter.attachView(this, getIntent().getIntExtra(EXTRA_CARD_ID_KEY, -1)); @@ -88,6 +92,7 @@ public class MainActivity extends BaseActivity implements MainContract.View, @Override public boolean onTabSelected(int position, boolean wasSelected) { presenter.onTabSelected(position, wasSelected); + appBar.setExpanded(true, true); return true; } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/settings/AboutScreen.java b/app/src/main/java/io/github/wulkanowy/ui/main/settings/AboutScreen.java deleted file mode 100644 index fe677de43..000000000 --- a/app/src/main/java/io/github/wulkanowy/ui/main/settings/AboutScreen.java +++ /dev/null @@ -1,67 +0,0 @@ -package io.github.wulkanowy.ui.main.settings; - -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.support.v7.preference.Preference; -import android.widget.Toast; - -import com.google.android.gms.oss.licenses.OssLicensesMenuActivity; - -import io.github.wulkanowy.BuildConfig; -import io.github.wulkanowy.R; -import io.github.wulkanowy.utils.AppConstant; - -public class AboutScreen extends SettingsFragment { - - public static final String SHARED_KEY_ABOUT_VERSION = "about_version"; - - public static final String SHARED_KEY_ABOUT_LICENSES = "about_osl"; - - public static final String SHARED_KEY_ABOUT_REPO = "about_repo"; - - private Preference.OnPreferenceClickListener onProgrammerListener = new Preference.OnPreferenceClickListener() { - private int clicks = 0; - - @Override - public boolean onPreferenceClick(Preference preference) { - Toast.makeText(getActivity(), getVersionToast(clicks++), Toast.LENGTH_SHORT).show(); - return true; - } - - private int getVersionToast(int click) { - if (0 == click) { - return R.string.about_programmer_step1; - } - - if (1 == click) { - return R.string.about_programmer_step2; - } - - if (9 > click) { - return R.string.about_programmer_step3; - } - - return R.string.about_programmer; - } - }; - - public AboutScreen() { - // silence is golden - } - - @Override - public void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - findPreference(SHARED_KEY_ABOUT_VERSION).setSummary(BuildConfig.VERSION_NAME); - findPreference(SHARED_KEY_ABOUT_VERSION).setOnPreferenceClickListener(onProgrammerListener); - findPreference(SHARED_KEY_ABOUT_REPO).setIntent(new Intent(Intent.ACTION_VIEW, Uri.parse(AppConstant.REPO_URL))); - findPreference(SHARED_KEY_ABOUT_LICENSES).setIntent(new Intent(getActivity(), OssLicensesMenuActivity.class) - .putExtra("title", getString(R.string.pref_about_osl))); - } - - @Override - public void onCreatePreferences(Bundle bundle, String rootKey) { - setPreferencesFromResource(R.xml.preferences, rootKey); - } -} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/settings/SettingsFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/settings/SettingsFragment.java index e08a49026..661706c08 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/settings/SettingsFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/settings/SettingsFragment.java @@ -1,18 +1,23 @@ package io.github.wulkanowy.ui.main.settings; +import android.content.Intent; import android.content.SharedPreferences; +import android.net.Uri; import android.os.Bundle; import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentTransaction; +import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceFragmentCompat; -import android.support.v7.preference.PreferenceScreen; +import android.widget.Toast; +import com.google.android.gms.oss.licenses.OssLicensesMenuActivity; + +import io.github.wulkanowy.BuildConfig; import io.github.wulkanowy.R; import io.github.wulkanowy.services.jobs.SyncJob; +import io.github.wulkanowy.utils.AppConstant; public class SettingsFragment extends PreferenceFragmentCompat - implements SharedPreferences.OnSharedPreferenceChangeListener, - PreferenceFragmentCompat.OnPreferenceStartScreenCallback{ + implements SharedPreferences.OnSharedPreferenceChangeListener { public static final String SHARED_KEY_START_TAB = "startup_tab"; @@ -28,6 +33,38 @@ public class SettingsFragment extends PreferenceFragmentCompat public static final String SHARED_KEY_SERVICES_MOBILE_DISABLED = "services_disable_mobile"; + public static final String SHARED_KEY_ABOUT_VERSION = "about_version"; + + public static final String SHARED_KEY_ABOUT_LICENSES = "about_osl"; + + public static final String SHARED_KEY_ABOUT_REPO = "about_repo"; + + private Preference.OnPreferenceClickListener onProgrammerListener = new Preference.OnPreferenceClickListener() { + private int clicks = 0; + + @Override + public boolean onPreferenceClick(Preference preference) { + Toast.makeText(getActivity(), getVersionToast(clicks++), Toast.LENGTH_SHORT).show(); + return true; + } + + private int getVersionToast(int click) { + if (0 == click) { + return R.string.about_programmer_step1; + } + + if (1 == click) { + return R.string.about_programmer_step2; + } + + if (9 > click) { + return R.string.about_programmer_step3; + } + + return R.string.about_programmer; + } + }; + @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { addPreferencesFromResource(R.xml.preferences); @@ -36,6 +73,12 @@ public class SettingsFragment extends PreferenceFragmentCompat @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + findPreference(SHARED_KEY_ABOUT_VERSION).setSummary(BuildConfig.VERSION_NAME); + findPreference(SHARED_KEY_ABOUT_VERSION).setOnPreferenceClickListener(onProgrammerListener); + findPreference(SHARED_KEY_ABOUT_REPO).setIntent(new Intent(Intent.ACTION_VIEW, Uri.parse(AppConstant.REPO_URL))); + findPreference(SHARED_KEY_ABOUT_LICENSES).setIntent(new Intent(getActivity(), OssLicensesMenuActivity.class) + .putExtra("title", getString(R.string.pref_about_osl))); } @Override @@ -43,21 +86,6 @@ public class SettingsFragment extends PreferenceFragmentCompat return this; } - @Override - public boolean onPreferenceStartScreen(PreferenceFragmentCompat preferenceFragmentCompat, - PreferenceScreen preferenceScreen) { - FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction(); - AboutScreen fragment = new AboutScreen(); - Bundle args = new Bundle(); - args.putString(PreferenceFragmentCompat.ARG_PREFERENCE_ROOT, preferenceScreen.getKey()); - fragment.setArguments(args); - ft.add(R.id.main_activity_container, fragment, preferenceScreen.getKey()); - ft.addToBackStack(preferenceScreen.getKey()); - ft.commit(); - - return true; - } - @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (key.equals(SHARED_KEY_SERVICES_ENABLE) || key.equals(SHARED_KEY_SERVICES_INTERVAL) diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index f9201ad46..3f8473d8c 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,37 +1,28 @@ - - - - - - + android:baselineAligned="false" + android:weightSum="1"> + android:layout_width="0dp" + android:layout_height="match_parent" + android:layout_weight="1"> + + + + + + android:layout_marginBottom="@dimen/bottom_navigation_height" + app:layout_behavior="@string/appbar_scrolling_view_behavior" /> - - + \ No newline at end of file diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index a2b1b368a..300bc0f39 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -11,13 +11,13 @@ + android:summary="@string/required_restart" + android:title="@string/pref_grades_summary_line_show" /> + android:summary="@string/required_restart" + android:title="@string/pref_attendance_present_show" /> + android:title="@string/pref_services_mobile_data" /> - - - - - - - - - - + + + + diff --git a/build.gradle b/build.gradle index 6af8545e5..760fb09f0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,12 @@ buildscript { repositories { - jcenter() mavenCentral() google() + jcenter() maven { url "https://plugins.gradle.org/m2/" } } dependencies { - classpath 'com.android.tools.build:gradle:3.1.2' + classpath 'com.android.tools.build:gradle:3.1.3' classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.2" classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.0' classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' @@ -70,9 +70,9 @@ ext { allprojects { repositories { - jcenter() mavenCentral() google() + jcenter() maven { url "https://jitpack.io" } } } From 7b7be1eef12c7ada1a4efebef24465201105c31f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sun, 10 Jun 2018 19:46:34 +0200 Subject: [PATCH 012/263] API fixes (#136) --- .../java/io/github/wulkanowy/api/Client.java | 7 +++++- .../io/github/wulkanowy/api/login/Login.java | 9 +++++++- .../wulkanowy/api/timetable/Timetable.java | 22 +++++++++++++++++-- .../api/timetable/TimetableTest.java | 1 + .../api/timetable/PlanLekcji-full.html | 15 ++++++++++++- 5 files changed, 49 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/io/github/wulkanowy/api/Client.java b/api/src/main/java/io/github/wulkanowy/api/Client.java index 869ed65e3..8bbae7ca8 100644 --- a/api/src/main/java/io/github/wulkanowy/api/Client.java +++ b/api/src/main/java/io/github/wulkanowy/api/Client.java @@ -62,6 +62,7 @@ public class Client { return; } + clearCookies(); this.symbol = new Login(this).login(email, password, symbol); logger.info("Login successful on {} at {}", getHost(), new Date()); } @@ -87,6 +88,10 @@ public class Client { return cookies.getItems(); } + public void clearCookies() { + cookies = new Cookies(); + } + String getHost() { return host; } @@ -216,7 +221,7 @@ public class Client { } if ("Błąd strony".equals(title)) { - throw new NotLoggedInErrorException(title + " " + doc.selectFirst("body") + ", status: " + code); + throw new NotLoggedInErrorException(title + " " + doc.body() + ", status: " + code); } return doc; diff --git a/api/src/main/java/io/github/wulkanowy/api/login/Login.java b/api/src/main/java/io/github/wulkanowy/api/login/Login.java index 04e1efc16..f6d4cd11e 100644 --- a/api/src/main/java/io/github/wulkanowy/api/login/Login.java +++ b/api/src/main/java/io/github/wulkanowy/api/login/Login.java @@ -5,6 +5,8 @@ import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.parser.Parser; import org.jsoup.select.Elements; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; @@ -21,6 +23,8 @@ public class Login { private Client client; + private static final Logger logger = LoggerFactory.getLogger(Login.class); + public Login(Client client) { this.client = client; } @@ -29,7 +33,8 @@ public class Login { Document certDoc = sendCredentials(email, password); if ("Błąd".equals(certDoc.title())) { - throw new NotLoggedInErrorException(certDoc.selectFirst("body").text()); + client.clearCookies(); + throw new NotLoggedInErrorException(certDoc.body().text()); } return sendCertificate(certDoc, symbol); @@ -88,6 +93,7 @@ public class Login { String title = targetDoc.title(); if ("Working...".equals(title)) { // on adfs login + logger.info("ADFS login"); title = sendCertData(targetDoc).title(); } @@ -96,6 +102,7 @@ public class Login { } if (!"Uonet+".equals(title)) { + logger.debug("Login failed. Body: {}", targetDoc.body()); throw new LoginErrorException("Expected page title `UONET+`, got " + title); } diff --git a/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java b/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java index 8a2b9e14e..95c40167c 100644 --- a/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java +++ b/api/src/main/java/io/github/wulkanowy/api/timetable/Timetable.java @@ -3,6 +3,8 @@ package io.github.wulkanowy.api.timetable; import org.apache.commons.lang3.StringUtils; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.ArrayList; @@ -13,8 +15,8 @@ import io.github.wulkanowy.api.VulcanException; import io.github.wulkanowy.api.generic.Lesson; import io.github.wulkanowy.api.generic.Week; -import static io.github.wulkanowy.api.DateTimeUtilsKt.getFormattedDate; import static io.github.wulkanowy.api.DateTimeUtilsKt.getDateAsTick; +import static io.github.wulkanowy.api.DateTimeUtilsKt.getFormattedDate; public class Timetable { @@ -22,6 +24,8 @@ public class Timetable { private SnP snp; + private static final Logger logger = LoggerFactory.getLogger(Timetable.class); + public Timetable(SnP snp) { this.snp = snp; } @@ -45,8 +49,13 @@ public class Timetable { private List getDays(Elements tableHeaderCells) { List days = new ArrayList<>(); + int numberOfDays = tableHeaderCells.size(); - for (int i = 2; i < 7; i++) { + if (numberOfDays > 7) { + logger.info("Number of days: {}", numberOfDays); + } + + for (int i = 2; i < numberOfDays; i++) { String[] dayHeaderCell = tableHeaderCells.get(i).html().split("
"); TimetableDay day = new TimetableDay(); @@ -127,6 +136,11 @@ public class Timetable { private void addLessonInfoFromElement(Lesson lesson, Element e) { Elements spans = e.select("span"); + if (spans.isEmpty()) { + logger.warn("Lesson span is empty"); + return; + } + addTypeInfo(lesson, spans); addNormalLessonInfo(lesson, spans); addChangesInfo(lesson, spans); @@ -213,6 +227,10 @@ public class Timetable { } private String[] getLessonAndGroupInfoFromSpan(Element span) { + if (!span.text().contains("[")) { + return new String[] {span.text(), ""}; + } + String[] subjectNameArray = span.text().split(" "); String groupName = subjectNameArray[subjectNameArray.length - 1]; diff --git a/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java b/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java index 1383b8307..7b3cce6ee 100644 --- a/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java +++ b/api/src/test/java/io/github/wulkanowy/api/timetable/TimetableTest.java @@ -156,6 +156,7 @@ public class TimetableTest extends StudentAndParentTestCase { Assert.assertEquals("poprzednio: Wychowanie fizyczne", full.getWeekTable().getDay(4).getLesson(2).getDescription()); Assert.assertEquals("egzamin", full.getWeekTable().getDay(3).getLesson(0).getDescription()); Assert.assertEquals("", full.getWeekTable().getDay(4).getLesson(1).getDescription()); + Assert.assertEquals("poprzednio: Zajęcia z wychowawcą", full.getWeekTable().getDay(4).getLesson(5).getDescription()); Assert.assertEquals("opis w uwadze bez klasy w spanie", full.getWeekTable().getDay(4).getLesson(4).getDescription()); Assert.assertEquals("", holidays.getWeekTable().getDay(3).getLesson(3).getDescription()); } diff --git a/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html b/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html index c6ade3a5c..c3dbfebe0 100644 --- a/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html +++ b/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html @@ -364,7 +364,20 @@ - + +
+ Tworzenie i administrowanie bazami danych [zaw2] + + + +
+
+ Zajęcia z wychowawcą + Małgorzata Kowal + 43 + (zmiana organizacji zajęć) +
+ 6 From 072c504d2b70bcd642d3db05a3891d4bbc0b8d36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Wed, 13 Jun 2018 03:07:34 +0200 Subject: [PATCH 013/263] Clean data user on bad user credentials (#138) --- .../java/io/github/wulkanowy/data/Repository.java | 6 ++++++ .../io/github/wulkanowy/data/RepositoryContract.java | 2 ++ .../io/github/wulkanowy/data/db/dao/DbContract.java | 2 ++ .../io/github/wulkanowy/data/db/dao/DbRepository.java | 11 +++++++++++ .../wulkanowy/data/db/shared/SharedPrefContract.java | 2 ++ .../data/db/shared/SharedPrefRepository.java | 6 ++++++ .../io/github/wulkanowy/services/jobs/SyncJob.java | 7 +++++++ 7 files changed, 36 insertions(+) diff --git a/app/src/main/java/io/github/wulkanowy/data/Repository.java b/app/src/main/java/io/github/wulkanowy/data/Repository.java index 1516c0279..ac6a8b42c 100644 --- a/app/src/main/java/io/github/wulkanowy/data/Repository.java +++ b/app/src/main/java/io/github/wulkanowy/data/Repository.java @@ -47,4 +47,10 @@ public class Repository implements RepositoryContract { public SyncContract getSyncRepo() { return synchronization; } + + @Override + public void cleanAllData() { + sharedPref.cleanSharedPref(); + database.recreateDatabase(); + } } diff --git a/app/src/main/java/io/github/wulkanowy/data/RepositoryContract.java b/app/src/main/java/io/github/wulkanowy/data/RepositoryContract.java index ffcfb0466..e4dbd26b8 100644 --- a/app/src/main/java/io/github/wulkanowy/data/RepositoryContract.java +++ b/app/src/main/java/io/github/wulkanowy/data/RepositoryContract.java @@ -17,4 +17,6 @@ public interface RepositoryContract { DbContract getDbRepo(); SyncContract getSyncRepo(); + + void cleanAllData(); } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbContract.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbContract.java index 34541d3ea..f32884f58 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbContract.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbContract.java @@ -30,4 +30,6 @@ public interface DbContract { long getCurrentSemesterId(); int getCurrentSemesterName(); + + void recreateDatabase(); } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbRepository.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbRepository.java index 43eee87ed..2c92c55d0 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbRepository.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbRepository.java @@ -1,9 +1,12 @@ package io.github.wulkanowy.data.db.dao; +import org.greenrobot.greendao.database.Database; + import java.util.List; import javax.inject.Inject; +import io.github.wulkanowy.data.db.dao.entities.DaoMaster; import io.github.wulkanowy.data.db.dao.entities.DaoSession; import io.github.wulkanowy.data.db.dao.entities.DiaryDao; import io.github.wulkanowy.data.db.dao.entities.Grade; @@ -109,4 +112,12 @@ public class DbRepository implements DbContract { SemesterDao.Properties.Current.eq(true) ).unique(); } + + @Override + public void recreateDatabase() { + Database database = daoSession.getDatabase(); + + DaoMaster.dropAllTables(database, true); + DaoMaster.createAllTables(database, true); + } } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefContract.java b/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefContract.java index b9d3fd14c..61795f642 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefContract.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefContract.java @@ -28,4 +28,6 @@ public interface SharedPrefContract { boolean isServicesEnable(); boolean isNotifyEnable(); + + void cleanSharedPref(); } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefRepository.java b/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefRepository.java index 11f43ca38..ca6624a8b 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefRepository.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/shared/SharedPrefRepository.java @@ -88,4 +88,10 @@ public class SharedPrefRepository implements SharedPrefContract { public boolean isMobileDisable() { return settingsSharedPref.getBoolean(SettingsFragment.SHARED_KEY_SERVICES_MOBILE_DISABLED, false); } + + @Override + public void cleanSharedPref() { + appSharedPref.edit().clear().apply(); + settingsSharedPref.edit().clear().apply(); + } } diff --git a/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java b/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java index b21363910..d0fc73d6f 100644 --- a/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java +++ b/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java @@ -21,6 +21,7 @@ import javax.inject.Inject; import dagger.android.AndroidInjection; import io.github.wulkanowy.R; +import io.github.wulkanowy.api.login.BadCredentialsException; import io.github.wulkanowy.data.RepositoryContract; import io.github.wulkanowy.data.db.dao.entities.Grade; import io.github.wulkanowy.data.sync.NotRegisteredUserException; @@ -82,6 +83,12 @@ public class SyncJob extends SimpleJobService { logError(e); stop(getApplicationContext()); + return JobService.RESULT_FAIL_NORETRY; + } catch (BadCredentialsException e) { + logError(e); + repository.cleanAllData(); + stop(getApplicationContext()); + return JobService.RESULT_FAIL_NORETRY; } catch (Exception e) { logError(e); From b63e28f9a928bd939010f3b034f2a46b1d9b034a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Borcz?= Date: Wed, 13 Jun 2018 18:53:42 +0200 Subject: [PATCH 014/263] Separate synchronization from login (#137) --- .../wulkanowy/ui/login/LoginActivity.java | 7 ++++ .../wulkanowy/ui/login/LoginContract.java | 4 +- .../wulkanowy/ui/login/LoginPresenter.java | 38 +++++++++++-------- .../github/wulkanowy/ui/login/LoginTask.java | 21 +++++++--- app/src/main/res/values-pl/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 6 files changed, 51 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.java b/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.java index 37f3e03ea..a0960af2c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.java +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginActivity.java @@ -14,6 +14,7 @@ import android.widget.ArrayAdapter; import android.widget.AutoCompleteTextView; import android.widget.EditText; import android.widget.TextView; +import android.widget.Toast; import javax.inject.Inject; @@ -217,6 +218,12 @@ public class LoginActivity extends BaseActivity implements LoginContract.View { return findViewById(R.id.login_activity_container); } + + @Override + public void onSyncFailed() { + Toast.makeText(getApplicationContext(), R.string.login_sync_error, Toast.LENGTH_LONG).show(); + } + private void onLoginProgressUpdate(String step, String message) { loginProgressText.setText(String.format("%1$s/2 - %2$s...", step, message)); } diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginContract.java b/app/src/main/java/io/github/wulkanowy/ui/login/LoginContract.java index 10f27f030..96bb49d6b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginContract.java @@ -33,6 +33,8 @@ public interface LoginContract { void showActionBar(boolean show); + void onSyncFailed(); + } interface Presenter extends BaseContract.Presenter { @@ -45,7 +47,7 @@ public interface LoginContract { void onLoginProgress(int step); - void onEndAsync(boolean success, Exception exception); + void onEndAsync(int success, Exception exception); void onCanceledAsync(); } diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java index 3ae1ce9e7..d8461bf3b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java @@ -83,22 +83,30 @@ public class LoginPresenter extends BasePresenter } @Override - public void onEndAsync(boolean success, Exception exception) { - if (success) { - FabricUtils.logRegister(true, getRepository().getDbRepo().getCurrentSymbol().getSymbol(), "Success"); - getView().openMainActivity(); - return; - } else if (exception instanceof BadCredentialsException) { - getView().setErrorPassIncorrect(); - getView().showSoftInput(); - } else if (exception instanceof AccountPermissionException) { - getView().setErrorSymbolRequired(); - getView().showSoftInput(); - } else { - FabricUtils.logRegister(false, symbol, exception.getMessage()); - getView().showMessage(getRepository().getResRepo().getErrorLoginMessage(exception)); + public void onEndAsync(int success, Exception exception) { + switch (success) { + case LoginTask.LOGIN_AND_SYNC_SUCCESS: + FabricUtils.logRegister(true, getRepository().getDbRepo().getCurrentSymbol().getSymbol(), "Success"); + getView().openMainActivity(); + return; + case LoginTask.SYNC_FAILED: + FabricUtils.logRegister(true, symbol, exception.getMessage()); + getView().onSyncFailed(); + getView().openMainActivity(); + return; + case LoginTask.LOGIN_FAILED: + if (exception instanceof BadCredentialsException) { + getView().setErrorPassIncorrect(); + getView().showSoftInput(); + } else if (exception instanceof AccountPermissionException) { + getView().setErrorSymbolRequired(); + getView().showSoftInput(); + } else { + FabricUtils.logRegister(false, symbol, exception.getMessage()); + getView().showMessage(getRepository().getResRepo().getErrorLoginMessage(exception)); + } + break; } - getView().showActionBar(true); getView().showLoginProgress(false); } diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginTask.java b/app/src/main/java/io/github/wulkanowy/ui/login/LoginTask.java index b22194da9..2938a836d 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginTask.java +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginTask.java @@ -2,7 +2,13 @@ package io.github.wulkanowy.ui.login; import android.os.AsyncTask; -public class LoginTask extends AsyncTask { +public class LoginTask extends AsyncTask { + + public final static int LOGIN_AND_SYNC_SUCCESS = 1; + + public final static int LOGIN_FAILED = -1; + + public final static int SYNC_FAILED = 2; private LoginContract.Presenter presenter; @@ -18,18 +24,23 @@ public class LoginTask extends AsyncTask { } @Override - protected Boolean doInBackground(Void... params) { + protected Integer doInBackground(Void... params) { try { publishProgress(1); presenter.onDoInBackground(1); + } catch (Exception e) { + exception = e; + return LOGIN_FAILED; + } + try { publishProgress(2); presenter.onDoInBackground(2); } catch (Exception e) { exception = e; - return false; + return SYNC_FAILED; } - return true; + return LOGIN_AND_SYNC_SUCCESS; } @Override @@ -38,7 +49,7 @@ public class LoginTask extends AsyncTask { } @Override - protected void onPostExecute(Boolean success) { + protected void onPostExecute(Integer success) { presenter.onEndAsync(success, exception); } diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 715e8adaa..af4fdf167 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -163,4 +163,5 @@ Końcowa średnia Podsumowanie Szczegóły + Podczas synchronizacji wystąpił błąd diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d7cf1806d..1dce9f0ac 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -158,4 +158,5 @@ Final average Summary Details + An error has occurred during synchronization From 11578aa735f74c3ee12327a6621c7c904640f099 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Thu, 14 Jun 2018 11:40:46 +0200 Subject: [PATCH 015/263] Add dark theme (#133) --- app/src/main/AndroidManifest.xml | 9 ++-- .../data/db/shared/SharedPrefContract.java | 2 + .../data/db/shared/SharedPrefRepository.java | 5 ++ .../wulkanowy/ui/base/BaseActivity.java | 1 + .../wulkanowy/ui/main/MainActivity.java | 11 ++-- .../attendance/AttendanceDialogFragment.java | 2 +- .../main/attendance/tab/AttendanceHeader.java | 20 ++------ .../ui/main/grades/GradesFragment.java | 2 + .../ui/main/settings/SettingsFragment.java | 50 +++++++++++++++++-- .../main/timetable/tab/TimetableHeader.java | 19 ++----- .../wulkanowy/ui/splash/SplashActivity.java | 5 ++ .../wulkanowy/ui/splash/SplashContract.java | 2 + .../wulkanowy/ui/splash/SplashPresenter.java | 1 + .../github/wulkanowy/utils/CommonUtils.java | 14 ++++++ app/src/main/res/drawable-night/ic_border.xml | 9 ++++ app/src/main/res/drawable/ic_border.xml | 2 +- .../res/drawable/ic_menu_attendance_24dp.xml | 4 +- .../main/res/drawable/ic_menu_exams_24dp.xml | 2 +- .../main/res/drawable/ic_menu_grade_26dp.xml | 4 +- .../main/res/drawable/ic_menu_other_24dp.xml | 4 +- .../res/drawable/ic_menu_timetable_24dp.xml | 4 +- app/src/main/res/drawable/ic_wrench_24dp.xml | 12 ----- app/src/main/res/layout/attendance_dialog.xml | 1 + app/src/main/res/layout/attendance_header.xml | 6 +-- .../main/res/layout/attendance_subitem.xml | 3 +- app/src/main/res/layout/current_week_tab.xml | 4 +- app/src/main/res/layout/exams_dialog.xml | 1 + app/src/main/res/layout/exams_header.xml | 4 +- app/src/main/res/layout/exams_subitem.xml | 2 +- .../res/layout/fragment_attendance_tab.xml | 8 +-- .../main/res/layout/fragment_exams_tab.xml | 6 +-- app/src/main/res/layout/fragment_grades.xml | 6 +-- .../res/layout/fragment_timetable_tab.xml | 6 +-- app/src/main/res/layout/grades_dialog.xml | 1 + app/src/main/res/layout/grades_header.xml | 8 +-- .../main/res/layout/grades_summary_header.xml | 2 +- app/src/main/res/layout/timetable_dialog.xml | 5 +- app/src/main/res/layout/timetable_header.xml | 6 +-- app/src/main/res/layout/timetable_subitem.xml | 7 ++- app/src/main/res/layout/timetable_widget.xml | 2 +- app/src/main/res/values-night/styles.xml | 17 +++++++ .../main/res/values-pl/prefernces_array.xml | 8 ++- app/src/main/res/values-pl/strings.xml | 1 + app/src/main/res/values/attrs.xml | 4 ++ app/src/main/res/values/colors.xml | 7 ++- app/src/main/res/values/prefernces_array.xml | 16 +++++- app/src/main/res/values/strings.xml | 2 + app/src/main/res/values/styles.xml | 5 +- app/src/main/res/xml/preferences.xml | 7 +++ 49 files changed, 221 insertions(+), 108 deletions(-) create mode 100644 app/src/main/res/drawable-night/ic_border.xml delete mode 100644 app/src/main/res/drawable/ic_wrench_24dp.xml create mode 100644 app/src/main/res/values-night/styles.xml create mode 100644 app/src/main/res/values/attrs.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 24b5e1888..dd982626a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,7 +14,6 @@ android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" - android:supportsRtl="true" android:theme="@style/WulkanowyTheme"> + /> + android:theme="@style/WulkanowyTheme.DarkActionBar" /> + android:theme="@style/WulkanowyTheme.DarkActionBar" /> { @@ -86,15 +86,6 @@ public class AttendanceHeader @BindView(R.id.attendance_header_free_name) TextView freeName; - @BindColor(R.color.secondary_text) - int secondaryColor; - - @BindColor(R.color.free_day) - int backgroundFreeDay; - - @BindColor(android.R.color.black) - int black; - private Context context; HeaderViewHolder(View view, FlexibleAdapter adapter) { @@ -117,16 +108,15 @@ public class AttendanceHeader setInactiveHeader(item.getAttendanceLessons().isEmpty()); } - private void setInactiveHeader(boolean inactive) { ((FrameLayout) getContentView()).setForeground(inactive ? null : getSelectableDrawable()); - dayName.setTextColor(inactive ? secondaryColor : black); + dayName.setTextColor(CommonUtils.getThemeAttrColor(context, + inactive ? android.R.attr.textColorSecondary : android.R.attr.textColorPrimary)); if (inactive) { - getContentView().setBackgroundColor(backgroundFreeDay); + getContentView().setBackgroundColor(CommonUtils.getThemeAttrColor(context, R.attr.colorControlHighlight)); } else { - getContentView().setBackgroundDrawable(context.getResources() - .getDrawable(R.drawable.ic_border)); + getContentView().setBackgroundDrawable(context.getResources().getDrawable(R.drawable.ic_border)); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java index 0d43b6833..ca1b949c7 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grades/GradesFragment.java @@ -88,7 +88,9 @@ public class GradesFragment extends BaseFragment implements GradesContract.View @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + menu.clear(); inflater.inflate(R.menu.grades_action_menu, menu); + super.onCreateOptionsMenu(menu, inflater); } @Override diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/settings/SettingsFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/settings/SettingsFragment.java index 661706c08..8bd930245 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/settings/SettingsFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/settings/SettingsFragment.java @@ -5,6 +5,7 @@ import android.content.SharedPreferences; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.Fragment; +import android.support.v7.app.AppCompatDelegate; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceFragmentCompat; import android.widget.Toast; @@ -14,6 +15,7 @@ import com.google.android.gms.oss.licenses.OssLicensesMenuActivity; import io.github.wulkanowy.BuildConfig; import io.github.wulkanowy.R; import io.github.wulkanowy.services.jobs.SyncJob; +import io.github.wulkanowy.ui.main.MainActivity; import io.github.wulkanowy.utils.AppConstant; public class SettingsFragment extends PreferenceFragmentCompat @@ -25,6 +27,8 @@ public class SettingsFragment extends PreferenceFragmentCompat public static final String SHARED_KEY_ATTENDANCE_PRESENT = "attendance_present"; + public static final String SHARED_KEY_THEME = "theme"; + public static final String SHARED_KEY_SERVICES_ENABLE = "services_enable"; public static final String SHARED_KEY_NOTIFY_ENABLE = "notify_enable"; @@ -39,6 +43,10 @@ public class SettingsFragment extends PreferenceFragmentCompat public static final String SHARED_KEY_ABOUT_REPO = "about_repo"; + private boolean isStarted; + + private boolean isVisible; + private Preference.OnPreferenceClickListener onProgrammerListener = new Preference.OnPreferenceClickListener() { private int clicks = 0; @@ -93,6 +101,20 @@ public class SettingsFragment extends PreferenceFragmentCompat launchServices(sharedPreferences.getBoolean(SHARED_KEY_SERVICES_ENABLE, true), sharedPreferences); } + + if (key.equals(SHARED_KEY_THEME)) { + setCurrentTheme(sharedPreferences); + } + } + + private void setCurrentTheme(SharedPreferences sharedPreferences) { + AppCompatDelegate.setDefaultNightMode(Integer.parseInt(sharedPreferences.getString(SHARED_KEY_THEME, "1"))); + getActivity().finish(); + startActivity(MainActivity + .getStartIntent(getContext()) + .putExtra(MainActivity.EXTRA_CARD_ID_KEY, 4) + ); + getActivity().overridePendingTransition(0, 0); } private void launchServices(boolean start, SharedPreferences sharedPref) { @@ -107,11 +129,25 @@ public class SettingsFragment extends PreferenceFragmentCompat } } + private void setTitle() { + getActivity().setTitle(R.string.settings_text); + } + @Override - public void setMenuVisibility(boolean menuVisible) { - super.setMenuVisibility(menuVisible); - if (menuVisible) { - getActivity().setTitle(R.string.settings_text); + public void setUserVisibleHint(boolean isVisibleToUser) { + super.setUserVisibleHint(isVisibleToUser); + isVisible = isVisibleToUser; + if (isVisible && isStarted) { + setTitle(); + } + } + + @Override + public void onStart() { + super.onStart(); + isStarted = true; + if (isVisible) { + setTitle(); } } @@ -128,4 +164,10 @@ public class SettingsFragment extends PreferenceFragmentCompat getPreferenceScreen().getSharedPreferences() .unregisterOnSharedPreferenceChangeListener(this); } + + @Override + public void onStop() { + super.onStop(); + isStarted = false; + } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeader.java b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeader.java index 93fab8220..cb877387e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeader.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/timetable/tab/TimetableHeader.java @@ -14,7 +14,6 @@ import org.apache.commons.lang3.builder.HashCodeBuilder; import java.util.List; -import butterknife.BindColor; import butterknife.BindView; import butterknife.ButterKnife; import eu.davidea.flexibleadapter.FlexibleAdapter; @@ -23,6 +22,7 @@ import eu.davidea.flexibleadapter.items.IFlexible; import eu.davidea.viewholders.ExpandableViewHolder; import io.github.wulkanowy.R; import io.github.wulkanowy.data.db.dao.entities.Day; +import io.github.wulkanowy.utils.CommonUtils; public class TimetableHeader extends AbstractExpandableHeaderItem { @@ -83,15 +83,6 @@ public class TimetableHeader @BindView(R.id.timetable_header_free_name) TextView freeName; - @BindColor(R.color.secondary_text) - int secondaryColor; - - @BindColor(R.color.free_day) - int backgroundFreeDay; - - @BindColor(android.R.color.black) - int black; - private Context context; HeaderViewHolder(View view, FlexibleAdapter adapter) { @@ -112,13 +103,13 @@ public class TimetableHeader private void setInactiveHeader(boolean inactive) { ((FrameLayout) getContentView()).setForeground(inactive ? null : getSelectableDrawable()); - dayName.setTextColor(inactive ? secondaryColor : black); + dayName.setTextColor(CommonUtils.getThemeAttrColor(context, + inactive ? android.R.attr.textColorSecondary : android.R.attr.textColorPrimary)); if (inactive) { - getContentView().setBackgroundColor(backgroundFreeDay); + getContentView().setBackgroundColor(CommonUtils.getThemeAttrColor(context, R.attr.colorControlHighlight)); } else { - getContentView().setBackgroundDrawable(context.getResources() - .getDrawable(R.drawable.ic_border)); + getContentView().setBackgroundDrawable(context.getResources().getDrawable(R.drawable.ic_border)); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java index 5e4dfec1f..21ce8ba5e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java @@ -1,6 +1,7 @@ package io.github.wulkanowy.ui.splash; import android.os.Bundle; +import android.support.v7.app.AppCompatDelegate; import javax.inject.Inject; @@ -38,6 +39,10 @@ public class SplashActivity extends BaseActivity implements SplashContract.View finish(); } + public void setCurrentThemeMode(int mode) { + AppCompatDelegate.setDefaultNightMode(mode); + } + @Override public void cancelNotifications() { new NotificationService(getApplicationContext()).cancelAll(); diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashContract.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashContract.java index 1a186eca3..a1c5ad723 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashContract.java +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashContract.java @@ -11,6 +11,8 @@ public interface SplashContract { void openMainActivity(); void cancelNotifications(); + + void setCurrentThemeMode(int mode); } interface Presenter extends BaseContract.Presenter { diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java index ff64b3cae..694233481 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.java @@ -18,6 +18,7 @@ public class SplashPresenter extends BasePresenter @Override public void attachView(@NonNull SplashContract.View view) { super.attachView(view); + getView().setCurrentThemeMode(getRepository().getSharedRepo().getCurrentTheme()); getView().cancelNotifications(); if (getRepository().getSharedRepo().isUserLoggedIn()) { diff --git a/app/src/main/java/io/github/wulkanowy/utils/CommonUtils.java b/app/src/main/java/io/github/wulkanowy/utils/CommonUtils.java index 8ec73faf7..9c7b35fb4 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/CommonUtils.java +++ b/app/src/main/java/io/github/wulkanowy/utils/CommonUtils.java @@ -1,7 +1,11 @@ package io.github.wulkanowy.utils; import android.app.Activity; +import android.content.Context; +import android.content.res.TypedArray; import android.net.Uri; +import android.support.annotation.AttrRes; +import android.support.annotation.ColorInt; import android.support.customtabs.CustomTabsIntent; import io.github.wulkanowy.R; @@ -37,4 +41,14 @@ public final class CommonUtils { return R.string.noColor_text; } } + + @ColorInt + public static int getThemeAttrColor(Context context, @AttrRes int colorAttr) { + final TypedArray array = context.obtainStyledAttributes(null, new int[]{colorAttr}); + try { + return array.getColor(0, 0); + } finally { + array.recycle(); + } + } } diff --git a/app/src/main/res/drawable-night/ic_border.xml b/app/src/main/res/drawable-night/ic_border.xml new file mode 100644 index 000000000..ca44eb29e --- /dev/null +++ b/app/src/main/res/drawable-night/ic_border.xml @@ -0,0 +1,9 @@ + + + + diff --git a/app/src/main/res/drawable/ic_border.xml b/app/src/main/res/drawable/ic_border.xml index dc33b8aa2..f46b3ad71 100644 --- a/app/src/main/res/drawable/ic_border.xml +++ b/app/src/main/res/drawable/ic_border.xml @@ -6,4 +6,4 @@ android:centerColor="@android:color/transparent" android:centerX="0.01" android:startColor="#60606060" /> - \ No newline at end of file + diff --git a/app/src/main/res/drawable/ic_menu_attendance_24dp.xml b/app/src/main/res/drawable/ic_menu_attendance_24dp.xml index fdef73225..c0df16d60 100644 --- a/app/src/main/res/drawable/ic_menu_attendance_24dp.xml +++ b/app/src/main/res/drawable/ic_menu_attendance_24dp.xml @@ -5,8 +5,8 @@ android:viewportHeight="24" android:viewportWidth="24"> - \ No newline at end of file + diff --git a/app/src/main/res/drawable/ic_menu_exams_24dp.xml b/app/src/main/res/drawable/ic_menu_exams_24dp.xml index 662945984..13179b7c3 100644 --- a/app/src/main/res/drawable/ic_menu_exams_24dp.xml +++ b/app/src/main/res/drawable/ic_menu_exams_24dp.xml @@ -4,7 +4,7 @@ android:viewportHeight="24" android:viewportWidth="24"> diff --git a/app/src/main/res/drawable/ic_menu_grade_26dp.xml b/app/src/main/res/drawable/ic_menu_grade_26dp.xml index 61506dada..3866cd3c7 100644 --- a/app/src/main/res/drawable/ic_menu_grade_26dp.xml +++ b/app/src/main/res/drawable/ic_menu_grade_26dp.xml @@ -4,8 +4,8 @@ android:viewportHeight="26" android:viewportWidth="26"> - \ No newline at end of file + diff --git a/app/src/main/res/drawable/ic_menu_other_24dp.xml b/app/src/main/res/drawable/ic_menu_other_24dp.xml index 9fed586b0..a07747245 100644 --- a/app/src/main/res/drawable/ic_menu_other_24dp.xml +++ b/app/src/main/res/drawable/ic_menu_other_24dp.xml @@ -5,7 +5,7 @@ android:viewportHeight="24" android:viewportWidth="24"> - \ No newline at end of file + diff --git a/app/src/main/res/drawable/ic_menu_timetable_24dp.xml b/app/src/main/res/drawable/ic_menu_timetable_24dp.xml index a689dc064..63880977b 100644 --- a/app/src/main/res/drawable/ic_menu_timetable_24dp.xml +++ b/app/src/main/res/drawable/ic_menu_timetable_24dp.xml @@ -5,7 +5,7 @@ android:viewportHeight="24" android:viewportWidth="24"> - \ No newline at end of file + diff --git a/app/src/main/res/drawable/ic_wrench_24dp.xml b/app/src/main/res/drawable/ic_wrench_24dp.xml deleted file mode 100644 index 8f3a86faa..000000000 --- a/app/src/main/res/drawable/ic_wrench_24dp.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/attendance_dialog.xml b/app/src/main/res/layout/attendance_dialog.xml index 916c993ca..4b0f1ff9a 100644 --- a/app/src/main/res/layout/attendance_dialog.xml +++ b/app/src/main/res/layout/attendance_dialog.xml @@ -144,6 +144,7 @@ android:background="?attr/selectableItemBackground" android:focusable="true" android:text="@string/generic_dialog_close" + android:textColor="?android:attr/android:textColorSecondary" android:textAllCaps="true" android:textSize="15sp" /> diff --git a/app/src/main/res/layout/attendance_header.xml b/app/src/main/res/layout/attendance_header.xml index 61dac6310..350b24522 100644 --- a/app/src/main/res/layout/attendance_header.xml +++ b/app/src/main/res/layout/attendance_header.xml @@ -39,7 +39,7 @@ android:layout_marginTop="5dp" android:maxLines="1" android:text="@string/app_name" - android:textColor="@color/secondary_text" + android:textColor="?android:attr/android:textColorSecondary" android:textSize="14sp" /> - \ No newline at end of file + android:textColor="?attr/colorPrimary" + android:textSize="14sp" /> diff --git a/app/src/main/res/layout/exams_dialog.xml b/app/src/main/res/layout/exams_dialog.xml index 47fd7bb70..72d4b8ddb 100644 --- a/app/src/main/res/layout/exams_dialog.xml +++ b/app/src/main/res/layout/exams_dialog.xml @@ -169,6 +169,7 @@ android:background="?attr/selectableItemBackground" android:focusable="true" android:text="@string/generic_dialog_close" + android:textColor="?android:attr/android:textColorSecondary" android:textAllCaps="true" android:textSize="15sp" /> diff --git a/app/src/main/res/layout/exams_header.xml b/app/src/main/res/layout/exams_header.xml index 3895ae2e2..7f7bf65f3 100644 --- a/app/src/main/res/layout/exams_header.xml +++ b/app/src/main/res/layout/exams_header.xml @@ -2,7 +2,7 @@ - \ No newline at end of file + diff --git a/app/src/main/res/layout/exams_subitem.xml b/app/src/main/res/layout/exams_subitem.xml index 52386de44..3f50f07c4 100644 --- a/app/src/main/res/layout/exams_subitem.xml +++ b/app/src/main/res/layout/exams_subitem.xml @@ -53,4 +53,4 @@ android:text="@string/app_name" android:textSize="13sp" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/fragment_attendance_tab.xml b/app/src/main/res/layout/fragment_attendance_tab.xml index f98e72804..4dc450b58 100644 --- a/app/src/main/res/layout/fragment_attendance_tab.xml +++ b/app/src/main/res/layout/fragment_attendance_tab.xml @@ -1,6 +1,6 @@ - @@ -43,8 +43,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="46dp" - android:text="@string/attendance_no_entries" android:gravity="center" + android:text="@string/attendance_no_entries" android:textSize="20sp" /> diff --git a/app/src/main/res/layout/fragment_exams_tab.xml b/app/src/main/res/layout/fragment_exams_tab.xml index e446b2fbe..433f5b1cb 100644 --- a/app/src/main/res/layout/fragment_exams_tab.xml +++ b/app/src/main/res/layout/fragment_exams_tab.xml @@ -25,7 +25,7 @@ android:layout_height="match_parent" android:gravity="center"> - - \ No newline at end of file + diff --git a/app/src/main/res/layout/fragment_grades.xml b/app/src/main/res/layout/fragment_grades.xml index f0642987a..1f177a600 100644 --- a/app/src/main/res/layout/fragment_grades.xml +++ b/app/src/main/res/layout/fragment_grades.xml @@ -144,7 +144,7 @@ android:layout_height="match_parent" android:gravity="center"> - - \ No newline at end of file + diff --git a/app/src/main/res/layout/fragment_timetable_tab.xml b/app/src/main/res/layout/fragment_timetable_tab.xml index 47aa51013..612b5df81 100644 --- a/app/src/main/res/layout/fragment_timetable_tab.xml +++ b/app/src/main/res/layout/fragment_timetable_tab.xml @@ -25,7 +25,7 @@ android:layout_height="match_parent" android:gravity="center"> - diff --git a/app/src/main/res/layout/grades_dialog.xml b/app/src/main/res/layout/grades_dialog.xml index 048f1e1b2..c5cf073ec 100644 --- a/app/src/main/res/layout/grades_dialog.xml +++ b/app/src/main/res/layout/grades_dialog.xml @@ -177,6 +177,7 @@ android:background="?attr/selectableItemBackground" android:focusable="true" android:text="@string/generic_dialog_close" + android:textColor="?android:attr/android:textColorSecondary" android:textAllCaps="true" android:textSize="15sp" /> diff --git a/app/src/main/res/layout/grades_header.xml b/app/src/main/res/layout/grades_header.xml index 41b98076b..b819dd54c 100644 --- a/app/src/main/res/layout/grades_header.xml +++ b/app/src/main/res/layout/grades_header.xml @@ -29,7 +29,7 @@ android:layout_below="@+id/grade_header_subject_text" android:layout_marginTop="5dp" android:text="@string/app_name" - android:textColor="@color/secondary_text" + android:textColor="?android:attr/android:textColorSecondary" android:textSize="12sp" /> @@ -192,6 +192,7 @@ android:background="?attr/selectableItemBackground" android:focusable="true" android:text="@string/generic_dialog_close" + android:textColor="?android:attr/android:textColorSecondary" android:textAllCaps="true" android:textSize="15sp" /> diff --git a/app/src/main/res/layout/timetable_header.xml b/app/src/main/res/layout/timetable_header.xml index 1e8ecec84..53ea8ce45 100644 --- a/app/src/main/res/layout/timetable_header.xml +++ b/app/src/main/res/layout/timetable_header.xml @@ -39,7 +39,7 @@ android:layout_marginTop="5dp" android:maxLines="1" android:text="@string/app_name" - android:textColor="@color/secondary_text" + android:textColor="?android:attr/android:textColorSecondary" android:textSize="14sp" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/timetable_subitem.xml b/app/src/main/res/layout/timetable_subitem.xml index 86b173b47..3c3cdc42a 100644 --- a/app/src/main/res/layout/timetable_subitem.xml +++ b/app/src/main/res/layout/timetable_subitem.xml @@ -13,7 +13,6 @@ android:foreground="?attr/selectableItemBackgroundBorderless" card_view:cardElevation="0dp"> - @@ -92,4 +91,4 @@ tool:ignore="contentDescription"/> - \ No newline at end of file + diff --git a/app/src/main/res/layout/timetable_widget.xml b/app/src/main/res/layout/timetable_widget.xml index c2f146ae3..acf8d238c 100644 --- a/app/src/main/res/layout/timetable_widget.xml +++ b/app/src/main/res/layout/timetable_widget.xml @@ -72,4 +72,4 @@ android:text="@string/widget_timetable_no_lesson" android:textColor="@android:color/black" android:textSize="20sp" /> - \ No newline at end of file + diff --git a/app/src/main/res/values-night/styles.xml b/app/src/main/res/values-night/styles.xml new file mode 100644 index 000000000..d0b4f53f9 --- /dev/null +++ b/app/src/main/res/values-night/styles.xml @@ -0,0 +1,17 @@ + + + + + + + diff --git a/app/src/main/res/values-pl/prefernces_array.xml b/app/src/main/res/values-pl/prefernces_array.xml index 4e66a3730..3731be408 100644 --- a/app/src/main/res/values-pl/prefernces_array.xml +++ b/app/src/main/res/values-pl/prefernces_array.xml @@ -9,4 +9,10 @@ 12 godzin 24 godzin - \ No newline at end of file + + Wyłączony + Włączony + Automatyczny + Używaj ustawień systemowych + + diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index af4fdf167..1af99630d 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -129,6 +129,7 @@ Pokazuj podsumowanie w ocenach Pokazuj obecność we frekwencji Wymagany restart + Ciemny motyw (Beta) Powiadomienia Pokazuj powiadomienia diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml new file mode 100644 index 000000000..3593e29e6 --- /dev/null +++ b/app/src/main/res/values/attrs.xml @@ -0,0 +1,4 @@ + + + + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 90f8c15e9..68145e051 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -10,8 +10,11 @@ #FFE68C #CE9AD2 #d32f2f + #cdcdcd + #4c4c4c #333 - #cdcdcd - #eee + + #303030 + #ffffff diff --git a/app/src/main/res/values/prefernces_array.xml b/app/src/main/res/values/prefernces_array.xml index 346b57c32..59f4fffed 100644 --- a/app/src/main/res/values/prefernces_array.xml +++ b/app/src/main/res/values/prefernces_array.xml @@ -12,6 +12,20 @@ 2 3 + + + Off + On + Auto + Follow system settings + + + 1 + 2 + 0 + -1 + + 10 minutes 30 minutes @@ -30,4 +44,4 @@ 720 1440 - \ No newline at end of file + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1dce9f0ac..21e63f5f2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -125,6 +125,8 @@ Show present in attendance Required restart + Dark theme (Beta) + Notifications Show the notifications diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index d72afb53c..1eb55f9d0 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,6 +1,6 @@ - - - - -
-

Frekwencja

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Lekcjaponiedziałek
31.08.2015
wtorek
01.09.2015
środa
02.09.2015
czwartek
03.09.2015
piątek
04.09.2015
0
1 -
- Uroczyste rozpoczęcie roku szkolnego 2015/2016 -
-
-
- Wychowanie do życia w rodzinie -
-
-
- Urządzenia techniki komputerowej -
-
2 -
- Język angielski -
-
-
- Język niemiecki -
-
-
- Urządzenia techniki komputerowej -
-
3 -
- Systemy operacyjne -
-
-
- Chemia -
-
-
- Urządzenia techniki komputerowej -
-
4 -
- Systemy operacyjne -
-
-
- Geografia -
-
-
- Urządzenia techniki komputerowej -
-
5 -
- Tworzenie stron internetowych -
-
-
- Matematyka -
-
-
- Język polski -
-
6 -
- Tworzenie stron internetowych -
-
-
- Fizyka -
-
-
- Matematyka -
-
7 -
- Wychowanie fizyczne -
-
-
- Język polski -
-
-
- Historia -
-
8 -
- Wychowanie fizyczne -
-
9
10
11
12
13
-

Statystyki

-
- - -
-

Frekwencja od początku roku szkolnego: 100,00%

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
IXXXIXIIIIIIIIIVVVIVIIVIIIRazem
Obecność14214313911013175126139921141211
Nieobecność nieusprawiedliwiona
Nieobecność usprawiedliwiona
Nieobecność z przyczyn szkolnych
Spóźnienie nieusprawiedliwione
Spóźnienie usprawiedliwione
Zwolnienie
-
-
wersja: 17.07.0002.24480
- - diff --git a/api/src/test/resources/io/github/wulkanowy/api/attendance/Frekwencja-full.html b/api/src/test/resources/io/github/wulkanowy/api/attendance/Frekwencja-full.html deleted file mode 100644 index aa9953053..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/attendance/Frekwencja-full.html +++ /dev/null @@ -1,498 +0,0 @@ - - - - - Witryna ucznia i rodzica – Frekwencja - - - -
-

Frekwencja

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Lekcjaponiedziałek
05.09.2016
wtorek
06.09.2016
środa
07.09.2016
czwartek
08.09.2016
piątek
09.09.2016
0
1 -
- Urządzenia techniki komputerowej -
-
-
- Multimedia i grafika komputerowa -
-
-
- Użytkowanie urządzeń peryferyjnych komputera -
-
-
- Religia -
-
2 -
- Urządzenia techniki komputerowej -
-
-
- Język niemiecki -
-
-
- Użytkowanie urządzeń peryferyjnych komputera -
-
-
- Język niemiecki -
-
-
- Sieci komputerowe i administrowanie sieciami -
-
3 -
- Urządzenia techniki komputerowej -
-
-
- Fizyka -
-
-
- Historia -
-
-
- Wychowanie fizyczne -
-
-
- Wiedza o kulturze -
-
4 -
- Naprawa komputera -
-
-
- Wychowanie fizyczne -
-
-
- Język angielski -
-
-
- Wychowanie fizyczne -
-
-
- Język polski -
-
5 -
- Sieci komputerowe i administrowanie sieciami -
-
-
- Metodologia programowania -
-
-
- Urządzenia techniki komputerowej -
-
-
- Matematyka -
-
-
- Metodologia programowania -
-
6 -
- Język niemiecki -
-
-
- Sieci komputerowe i administrowanie sieciami -
-
-
- Język polski -
-
-
- Podstawy przedsiębiorczości -
-
-
- Matematyka -
-
7 -
- Fizyka -
-
-
- Język polski -
-
-
- Systemy operacyjne -
-
-
- Zajęcia z wychowawcą -
-
-
- Religia -
-
8 -
- Naprawa komputera -
-
-
- Systemy operacyjne -
-
-
- Urządzenia techniki komputerowej -
-
-
- Zajęcia z wychowawcą -
-
9
10
11
12
13
-

Statystyki

-
- - -
-

Frekwencja od początku roku szkolnego: 80,94%

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
IXXXIXIIIIIIIIIVVVIVIIVIIIRazem
Obecność1351031085437100339010359822
Nieobecność nieusprawiedliwiona246
Nieobecność usprawiedliwiona627293044161327192
Nieobecność z przyczyn szkolnych77
Spóźnienie nieusprawiedliwione41222112
Spóźnienie usprawiedliwione11
Zwolnienie112
-
-
wersja: 17.07.0002.24480
- - diff --git a/api/src/test/resources/io/github/wulkanowy/api/exams/Sprawdziany-empty.html b/api/src/test/resources/io/github/wulkanowy/api/exams/Sprawdziany-empty.html deleted file mode 100644 index bf1032b4d..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/exams/Sprawdziany-empty.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - Witryna ucznia i rodzica – Terminarz sprawdzianów - - -
-

Sprawdziany

-

Tydzień 30.04.2018 - 06.05.2018

-

Nie zaplanowano żadnych sprawdzianów na wybrany tydzień

- -
-
wersja: 17.09.0009.26859
- - diff --git a/api/src/test/resources/io/github/wulkanowy/api/exams/Sprawdziany-one-per-day.html b/api/src/test/resources/io/github/wulkanowy/api/exams/Sprawdziany-one-per-day.html deleted file mode 100644 index 81b3052b2..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/exams/Sprawdziany-one-per-day.html +++ /dev/null @@ -1,143 +0,0 @@ - - - - - Witryna ucznia i rodzica – Terminarz sprawdzianów - - -
-

Sprawdziany

-

Tydzień 23.10.2017 - 29.10.2017

-
-

poniedziałek, 23.10.2017

-
-
-
Przedmiot i grupa:
-
Sieci komputerowe 3Ti|zaw2
-
-
-
Rodzaj sprawdzianu:
-
Sprawdzian
-
-
-
Opis:
-
Łącza danych
-
-
-
Nauczyciel i data wpisu:
-
Adam Wiśniewski [AW], 16.10.2017
-
-
-
-
-

wtorek, 24.10.2017

-
-
-
Przedmiot i grupa:
-
Język angielski 3Ti|J1
-
-
-
Rodzaj sprawdzianu:
-
Sprawdzian
-
-
-
Opis:
-
Czasy teraźniejsze
-
-
-
Nauczyciel i data wpisu:
-
Natalia Nowak [NN], 17.10.2017
-
-
-
-
-

środa, 25.10.2017

-
-
-
Przedmiot i grupa:
-
Język angielski 3Ti|J2
-
-
-
Rodzaj sprawdzianu:
-
Sprawdzian
-
-
-
Opis:
-
słownictwo (zdrowie)
-
-
-
Nauczyciel i data wpisu:
-
Natalia Nowak [NN], 17.10.2017
-
-
-
-
-
Przedmiot i grupa:
-
Metodologia programowania 3Ti|zaw1
-
-
-
Rodzaj sprawdzianu:
-
Kartkówka
-
-
-
Opis:
-
programowanie obiektowe
-
-
-
Nauczyciel i data wpisu:
-
Małgorzata Nowacka [MN], 16.10.2017
-
-
-
-
-

czwartek, 26.10.2017

-
-
-
Przedmiot i grupa:
-
Język polski 3Ti
-
-
-
Rodzaj sprawdzianu:
-
Sprawdzian
-
-
-
Opis:
-
Dwudziestolecie
-
-
-
Nauczyciel i data wpisu:
-
Czerwieńska Agata [CA], 16.10.2017
-
-
-
-
-

piątek, 27.10.2017

-
-
-
Przedmiot i grupa:
-
Metodologia programowania 3Ti|zaw2
-
-
-
Rodzaj sprawdzianu:
-
Sprawdzian
-
-
-
Opis:
-
-
-
-
Nauczyciel i data wpisu:
-
Małgorzata Nowacka [MN], 16.10.2017
-
-
-
-
-
- -
-
wersja: 17.08.0001.24874
- - diff --git a/api/src/test/resources/io/github/wulkanowy/api/grades/OcenyWszystkie-filled.html b/api/src/test/resources/io/github/wulkanowy/api/grades/OcenyWszystkie-filled.html deleted file mode 100644 index d0cdb6643..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/grades/OcenyWszystkie-filled.html +++ /dev/null @@ -1,116 +0,0 @@ - - - - - Witryna ucznia i rodzica – Oceny - - -
-

Oceny

-
-
- - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PrzedmiotOcena cząstkowaOpisWagaDataNauczyciel
ZachowanieBrak ocen
Zajęcia z wychowawcą - 5 - A1, Dzień Kobiet w naszej klasie1,0021.03.2017Patryk Maciejewski
Edukacja dla bezpieczeństwa - 4- - S1, PIERWSZA POMOC I RESUSCYTACJA5,0031.03.2017Weronika Ratajczak
Fizyka - 2 - O, Odpowiedź3,0025.06.2017Jakub Michalak
Język angielski - 5 - BW3, Writing3,0002.06.2017Oliwia Woźniak
Wiedza o społeczeństwieBrak ocen
Wychowanie fizyczne1STR8,0002.04.2017Klaudia Dziedzic
Język polski1K, Kordian5,0006.02.2017Amelia Stępień
Język polski5+Odp, Kordian5,0011.05.2017Amelia Stępień
-
-
wersja: 17.02.0000.23328
- - diff --git a/api/src/test/resources/io/github/wulkanowy/api/grades/OcenyWszystkie-subjects-average.html b/api/src/test/resources/io/github/wulkanowy/api/grades/OcenyWszystkie-subjects-average.html deleted file mode 100644 index 023b5405e..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/grades/OcenyWszystkie-subjects-average.html +++ /dev/null @@ -1,70 +0,0 @@ - - - - - Witryna ucznia i rodzica – Oceny - - -
-

Oceny

-
-
- - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PrzedmiotOceny cząstkoweŚredniaPrzewidywana ocena rocznaOcena roczna
ZachowanieBrak ocen-bardzo dobrebardzo dobre
Język polski03,53-dobry
Wychowanie fizyczne05,05bardzo dobrycelujący
Język angielski04,44/5bardzo dobry
Wiedza o społeczeństwieBrak ocen---
-
-
wersja: 17.02.0000.23328
- - diff --git a/api/src/test/resources/io/github/wulkanowy/api/grades/OcenyWszystkie-subjects.html b/api/src/test/resources/io/github/wulkanowy/api/grades/OcenyWszystkie-subjects.html deleted file mode 100644 index 0f6da4148..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/grades/OcenyWszystkie-subjects.html +++ /dev/null @@ -1,64 +0,0 @@ - - - - - Witryna ucznia i rodzica – Oceny - - -
-

Oceny

-
-
- - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PrzedmiotOceny cząstkowePrzewidywana ocena rocznaOcena roczna
Zachowanie-bardzo dobrebardzo dobre
Praktyka zawodowa--celujący
Metodologia programowania-bardzo dobrycelujący
Podstawy przedsiębiorczości-3/4dostateczny
Wychowanie do życia w rodzinie---
-
-
wersja: 17.05.0000.24042
- - diff --git a/api/src/test/resources/io/github/wulkanowy/api/homework/ZadaniaDomowe.html b/api/src/test/resources/io/github/wulkanowy/api/homework/ZadaniaDomowe.html deleted file mode 100644 index ec68d2abd..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/homework/ZadaniaDomowe.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - Witryna ucznia i rodzica – Zadania domowe - - -
-

Zadania domowe

- -

poniedziałek, 23.10.2017

- -
-
-
Przedmiot:
-
Sieci komputerowe i administrowanie sieciami
-
-
-
Opis:
-
Zadania egzaminacyjne -
-
-
-
Nauczyciel i data wpisu:
-
Słowacki Juliusz [SJ], 16.10.2017
-
-
-
-
-
Przedmiot:
-
Naprawa komputera
-
-
-
Opis:
-
Test diagnozujący
-
-
-
Nauczyciel i data wpisu:
-
Mickiewicz Adam [MA], 25.10.2017
-
-
- -
-
wersja: 18.02.0007.28151
- - diff --git a/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-brak-dostepu.html b/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-brak-dostepu.html deleted file mode 100644 index 2911f1d24..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-brak-dostepu.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - Logowanie - - -
-
- Adres example@wulkanowy.io nie został zarejestrowany w dzienniku uczniowskim jako adres rodzica, bądź ucznia. - Jeśli jesteś rodzicem (prawnym opiekunem) ucznia (lub uczniem) szkoły korzystającej z dziennika „UONET +” udaj się do - wychowawcy i poproś o wprowadzenie Twojego adresu e-mail do Twoich danych. -
-
- - diff --git a/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-certyfikat.html b/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-certyfikat.html deleted file mode 100644 index f53a34856..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-certyfikat.html +++ /dev/null @@ -1,17 +0,0 @@ - - - Working... - - -
- - - - -
- - - diff --git a/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-error.html b/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-error.html deleted file mode 100644 index afb044d7f..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-error.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - Logowanie (demo123) - - -
-
-
-

Logowanie

-
-
- Zła nazwa użytkownika lub hasło -
-
-
- - - diff --git a/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-notLoggedIn.html b/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-notLoggedIn.html deleted file mode 100644 index f961bf82c..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-notLoggedIn.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - Dziennik UONET+ - - -
-
-
-
-
- - Zaloguj się -
-
-
-
Uonet+ wersja 17.09.0007.26300
-
-
- - diff --git a/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-success.html b/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-success.html deleted file mode 100644 index f35e68668..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-success.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - Uonet+ - - -
-
-
- example@wulkanowy.io (wyloguj) -
-
- -
- - diff --git a/api/src/test/resources/io/github/wulkanowy/api/login/PrzerwaTechniczna.html b/api/src/test/resources/io/github/wulkanowy/api/login/PrzerwaTechniczna.html deleted file mode 100644 index 062f9b60c..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/login/PrzerwaTechniczna.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - Przerwa techniczna - - -
-
-
-

Przerwa techniczna

-

Aktualnie trwają prace konserwacyjne. Witryna będzie dostępna za kilka minut.

> -
- -
-
- - diff --git a/api/src/test/resources/io/github/wulkanowy/api/login/cert-no-symbols.xml b/api/src/test/resources/io/github/wulkanowy/api/login/cert-no-symbols.xml deleted file mode 100644 index ca14bdf55..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/login/cert-no-symbols.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Default - - - - - - diff --git a/api/src/test/resources/io/github/wulkanowy/api/login/cert-stock.xml b/api/src/test/resources/io/github/wulkanowy/api/login/cert-stock.xml deleted file mode 100644 index 31aa19b27..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/login/cert-stock.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - Default - demo12345 - incorrect value - warszawa - asdf - asdfsdf - - - - - - diff --git a/api/src/test/resources/io/github/wulkanowy/api/messages/GetTrescWiadomosci.json b/api/src/test/resources/io/github/wulkanowy/api/messages/GetTrescWiadomosci.json deleted file mode 100644 index 1ba54a32c..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/messages/GetTrescWiadomosci.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "success": true, - "data": { - "Id": 12345, - "Tresc": "Witam, …. \nPozdrawiam Krzysztof Czerkas" - } -} diff --git a/api/src/test/resources/io/github/wulkanowy/api/messages/GetWiadomosciOdebrane.json b/api/src/test/resources/io/github/wulkanowy/api/messages/GetWiadomosciOdebrane.json deleted file mode 100644 index 326390ed6..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/messages/GetWiadomosciOdebrane.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "success": true, - "data": [ - { - "Nieprzeczytana": false, - "Data": "2016-03-15 09:00:00", - "Tresc": null, - "Temat": "Wycieczka", - "NadawcaNazwa": "Kowalski Jan", - "IdWiadomosci": 1234, - "IdNadawca": 4321, - "Id": 12345 - }, - { - "Nieprzeczytana": true, - "Data": "2016-04-20 22:00:00", - "Tresc": null, - "Temat": "\"Dzień dobrego słowa\"", - "NadawcaNazwa": "Pazura Agnieszka", - "IdWiadomosci": 1235, - "IdNadawca": 12, - "Id": 12346 - }, - { - "Nieprzeczytana": false, - "Data": "2016-04-29 10:00:00", - "Tresc": null, - "Temat": "Rozdajemy oceny celujące", - "NadawcaNazwa": "Kowalski Jan", - "IdWiadomosci": 1236, - "IdNadawca": 4321, - "Id": 12347 - } - ] -} diff --git a/api/src/test/resources/io/github/wulkanowy/api/messages/GetWiadomosciUsuniete-empty.json b/api/src/test/resources/io/github/wulkanowy/api/messages/GetWiadomosciUsuniete-empty.json deleted file mode 100644 index 36f89aa1e..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/messages/GetWiadomosciUsuniete-empty.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "success": true, - "data": [] -} diff --git a/api/src/test/resources/io/github/wulkanowy/api/messages/PageError.html b/api/src/test/resources/io/github/wulkanowy/api/messages/PageError.html deleted file mode 100644 index ae976af1f..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/messages/PageError.html +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - Błąd strony - - - -
- -
-
- Wystąpił nieoczekiwany błąd -
-
Wystąpił błąd aplikacji. Prosimy zalogować się ponownie. Jeśli problem będzie się powtarzał, prosimy o kontakt z serwisem.
-
-
-
- -
- - diff --git a/api/src/test/resources/io/github/wulkanowy/api/messages/UndefinedError.txt b/api/src/test/resources/io/github/wulkanowy/api/messages/UndefinedError.txt deleted file mode 100644 index c8d55a96c..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/messages/UndefinedError.txt +++ /dev/null @@ -1 +0,0 @@ -The custom error module does not recognize this error. \ No newline at end of file diff --git a/api/src/test/resources/io/github/wulkanowy/api/mobile/DostepMobilny-filled.html b/api/src/test/resources/io/github/wulkanowy/api/mobile/DostepMobilny-filled.html deleted file mode 100644 index 9fbfd4039..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/mobile/DostepMobilny-filled.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - Witryna ucznia i rodzica – dostęp mobilny - - - -
-

Dostęp mobilny

- -
-

Zarejestrowane urządzenia

-
- - - - - - - - - - - - - - - - - - - - -
UrządzenieData rejestracji
google Android SDK built for x86 (Android 8.1.0)20.01.2018 godz: 22:35:30 - Wyrejestruj -
google (Android SDK) built for x86 (Android 8.1.0)20.01.2018 godz: 22:35:30 - Wyrejestruj -
-
- -
wersja: 18.01.0001.27311
- - diff --git a/api/src/test/resources/io/github/wulkanowy/api/mobile/Rejestruj.html b/api/src/test/resources/io/github/wulkanowy/api/mobile/Rejestruj.html deleted file mode 100644 index 15d08d07c..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/mobile/Rejestruj.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - Witryna ucznia i rodzica – Rejestracja urządzenia mobilnego - - - -
-

Rejestracja urządzenia mobilnego

-
- Za pomocą aplikacji "Dzienniczek+" zeskanuj kod QR. - Kod QR - Token: 3S1A1B2C - Symbol: Default - PIN: 1234567 -
-
-
wersja: 18.01.0001.27311
- - diff --git a/api/src/test/resources/io/github/wulkanowy/api/notes/UwagiOsiagniecia-empty.html b/api/src/test/resources/io/github/wulkanowy/api/notes/UwagiOsiagniecia-empty.html deleted file mode 100644 index b15bb6e70..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/notes/UwagiOsiagniecia-empty.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - Witryna ucznia i rodzica – Uwagi i osiągnięcia - - -
-
-

Uwagi

-

Brak informacji do wyświetlenia

-
-
-

Osiągnięcia

-

Brak informacji do wyświetlenia

-
-
-
wersja: 17.05.0000.24042
- - diff --git a/api/src/test/resources/io/github/wulkanowy/api/notes/UwagiOsiagniecia-filled.html b/api/src/test/resources/io/github/wulkanowy/api/notes/UwagiOsiagniecia-filled.html deleted file mode 100644 index 50e740585..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/notes/UwagiOsiagniecia-filled.html +++ /dev/null @@ -1,65 +0,0 @@ - - - - - Witryna ucznia i rodzica – Uwagi i osiągnięcia - - -
-
-

Uwagi

-

06.06.2017

-
-
-
Nauczyciel:
-
Jan Kowalski [JK]
-
-
-
Kategoria:
-
Zaangażowanie społeczne
-
-
-
Treść:
-
Pomoc przy pikniku charytatywnym
-
-
-

01.12.2016

-
-
-
Nauczyciel:
-
Ochocka Zofia [PZ]
-
-
-
Kategoria:
-
Reprezentowanie szkoły
-
-
-
Treść:
-
Udział w przygotowaniu spektaklu
-
-
-

01.10.2016

-
-
-
Nauczyciel:
-
Kochański Leszek [KL]
-
-
-
Kategoria:
-
Zachowanie na lekcji
-
-
-
Treść:
-
Przeszkadzanie w prowadzeniu lekcji
-
-
-
-
-

Osiągnięcia

-
I miejsce w ogólnopolskim konkursie ortograficznym
-
III miejsce w ogólnopolskim konkursie plastycznym
-
-
-
wersja: 17.05.0000.24042
- - diff --git a/api/src/test/resources/io/github/wulkanowy/api/school/Szkola.html b/api/src/test/resources/io/github/wulkanowy/api/school/Szkola.html deleted file mode 100644 index 05a698a04..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/school/Szkola.html +++ /dev/null @@ -1,136 +0,0 @@ - - - - - Witryna ucznia i rodzica – Szkoła i nauczyciele - - -
-

Szkoła

-
-
- Nazwa szkoły: - Zespół Szkół nr 64 -
-
- Adres szkoły: - ul. Wiśniowa 128, 01-234 Rogalowo, Nibylandia -
-
- Telefon: - 55 5555555 -
-
- Imię i nazwisko dyrektora: - Antoni Sobczyk -
-
- Imię i nazwisko pedagoga: - Zofia Czerwińska [ZC], Aleksander Krzemiński [AK], Karolina Kowalska [KK], Bartek Dąbrowski [BD] -
-
-

Nauczyciele

-

- Klasa: 1a, Wychowawcy: - Karolina Kowalska [AN], Antoni Sobczyk [AS]

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Lp.PrzedmiotNauczyciel
1BiologiaKarolina Kowalska [AN]
2ChemiaZofia Czerwińska [NA]
3Edukacja dla bezpieczeństwaAleksandra Krajewska [AK]
4FizykaStanisław Krupa [BS]
5GeografiaAleksandra Wójtowicz [AW]
6HistoriaSara Wierzbicka [KB]
7Język angielskiKarolina Kowalska [AN], Mateusz Kowal [MK], Amelia Mazur [AM]
8Język niemieckiMateusz Kowal [MK], Barbara Markowska [BM]
9Język polskiMichał Mazur [MM]
10MatematykaSzymon Wojciechowski [SW]
11PlastykaMichał Mazur [MM]
12ReligiaMaja Wiśniewska [M]
13Wiedza o społeczeństwieKarolina Kowalska [AN]
14Wychowanie do życia w rodzinieZofia Czerwińska [NA]
15Wychowanie fizyczneKarolina Kowalska [AN], Liliana Kowal [LK]
16Zajęcia techniczneBartek Dąbrowski [BD]
17Zajęcia z wychowawcąKarolina Kowalska [AN]
-
-
wersja: 17.02.0000.23328
- - diff --git a/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html b/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html deleted file mode 100644 index c3dbfebe0..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-full.html +++ /dev/null @@ -1,567 +0,0 @@ - - - - - Witryna ucznia i rodzica – Plan lekcji - - - -
-

Plan lekcji

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
LekcjaPora lekcjiponiedziałek
19.06.2017
wtorek
20.06.2017
środa
21.06.2017
czwartek
22.06.2017
piątek
23.06.2017
007:10 07:55 -
- Fizyka [zaw2] - - Bączek Grzegorz - 19 - (uczniowie zwolnieni do domu) -
-
-
- Metodologia programowania [zaw2] - - - 32 -
-
-
- Religia - Cyranka Krystian - 3 - Wychowanie do życia w rodzinie - Nowak Jadwiga - 3 - (zastępstwo) -
-
-
- Język polski - - 16 - (oddział nieobecny) -
- -
egzamin
-
-
- Uroczyste zakończenie roku szkolnego - Baran Małgorzata - 37 -
-
108:00 08:45 -
- Język angielski [J1] - - Kobczyk Iwona - -
-
-
- Wychowanie fizyczne [zaw2] - - - G3 - (przeniesiona z lekcji 7, 01.12.2017) -
-
- Metodologia programowania [zaw2] - - Baran Małgorzata - 36 - (zmiana organizacji zajęć) -
-
-
- Użytkowanie urządzeń peryferyjnych komputera [zaw2] - - Bączek Robert - -
-
-
- Wychowanie fizyczne [zaw1] - - Jarocki Krzysztof - G4 - Wychowanie fizyczne [zaw1] - - Nowicka Irena - G4 - (zastępstwo) -
-
-
- Uroczyste rozpoczecie roku szkolnego 2017/2018 - - -
-
- Uroczyste rozpoczecie roku szkolnego 2017/2018 - - -
-
208:50 09:35 -
- Język polski - Bocian Natalia - -
-
-
- Język niemiecki [J1] - - Rożeniec Honorata - 25 - (okienko dla uczniów) -
-
- Język polski - Bocian Natalia - - (przeniesiona z lekcji 7, 20.06.2017) -
-
- Język polski - Bocian Natalia - -
-
-
- Urządzenia techniki komputerowej [zaw2] - - Bocian Grzegorz - -
-
-
- Matematyka - Baran Małgorzata - -
-
-
- Język niemiecki [wf_grupa_2] - - - -
-
- Wychowanie fizyczne [wf_grupa_2] - - Nauczycielel - 106 -
-
309:40 10:25 -
- Język polski - Bocian Natalia - -
-
-
- Fizyka - Bączek Grzegorz - 19 - (okienko dla uczniów) -
-
- Wychowanie fizyczne [wf2] - - Nowicka Irena - - (przeniesiona z lekcji 4, 20.06.2017) -
-
- Wychowanie fizyczne [wf2] - - Nowicka Irena - -
-
-
- Metodologia programowania [zaw2] - - Baran Małgorzata - -
-
-
- Wychowanie fizyczne [wf2] - - Nowicka Irena - -
-
-
- Religia - Cyranka Krystian - 3 - Wychowanie do życia w rodzinie - Nowak Jadwiga - 3 - bez nawiasów -
-
410:40 11:25 -
- Urządzenia techniki komputerowej [zaw2] - - Bocian Grzegorz - -
-
-
- Wychowanie fizyczne [wf2] - - Nowicka Irena - - (przeniesiona na lekcję 3, 20.06.2017) -
-
-
- Matematyka - Baran Małgorzata - -
-
-
- Wychowanie fizyczne [wf2] - - Nowicka Irena - -
-
-
- Język polski - - 16 - (oddział nieobecny) -
- -
opis w uwadze bez klasy w spanie
-
511:30 12:15 -
- Urządzenia techniki komputerowej [zaw2] - - Bocian Grzegorz - -
-
-
- Podstawy przedsiębiorczości - Bogatka Anna - W12 - (okienko dla uczniów) -
-
-
- Religia - Cyranka Krystian - -
-
-
- Sieci komputerowe i administrowanie sieciami [zaw2] - - Rożeniec Piotr - -
-
-
- Tworzenie i administrowanie bazami danych [zaw2] - - - -
-
- Zajęcia z wychowawcą - Małgorzata Kowal - 43 - (zmiana organizacji zajęć) -
-
612:20 13:05 -
- Matematyka - Baran Małgorzata - -
-
-
- Podstawy przedsiębiorczości - Bogatka Anna - W12 - (okienko dla uczniów) -
-
-
- Język angielski [J1] - - Brodziec Sylwia - -
-
-
- Religia - Cyranka Krystian - -
-
713:10 13:55 -
- Fizyka - Bączek Grzegorz - 33 - (okienko dla uczniów) -
-
-
- Język polski - Bocian Natalia - - (przeniesiona na lekcję 2, 20.06.2017) -
-
-
- Multimedia i grafika komputerowa [zaw2] - - Bocian Konrad - -
-
-
- Wiedza o kulturze - Bocian Natalia - -
-
814:00 14:45 -
- Zajęcia z wychowawcą - Baran Małgorzata - -
-
-
- Naprawa komputera [zaw2] - - Kraska Maciej - 32 - (okienko dla uczniów) -
-
-
- Systemy operacyjne [zaw2] - - Kraska Maciej - 32 -
-
914:50 15:35 -
- Wychowanie fizyczne [zaw2] - - - G3 - (przeniesiona z lekcji 7, 01.12.2017) -
-
- -
-
-
- Język niemiecki [J1] - - Rożeniec Honorata - 25 - (uczniowie zwolnieni do domu) -
-
1015:40 16:25
1116:35 17:20
1217:25 18:10
1318:15 19:00
-
-
-
- Kursywa- planowane -
-
- Zwykła czcionka- zrealizowane -
-
- Przekreślone- odwołane lub przeniesione -
-
- Pogrubione- nowe lekcje, przeniesione z innego terminu, zastępstwa -
-
-
-
wersja: 17.05.0000.24042
- - diff --git a/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-holidays.html b/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-holidays.html deleted file mode 100644 index 09555cf3f..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-holidays.html +++ /dev/null @@ -1,156 +0,0 @@ - - - - - Witryna ucznia i rodzica – Plan lekcji - - -
-

Plan lekcji

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
LekcjaPora lekcjiponiedziałek
31.07.2017
Ferie letnie
wtorek
01.08.2017
Ferie letnie
środa
02.08.2017
Ferie letnie
czwartek
03.08.2017
Ferie letnie
piątek
04.08.2017
Ferie letnie
007:10 07:55
108:00 08:45
208:50 09:35
309:40 10:25
410:40 11:25
511:30 12:15
612:20 13:05
713:10 13:55
814:00 14:45
914:50 15:35
1015:40 16:25
1116:35 17:20
1217:25 18:10
1318:15 19:00
-
-
-
wersja: 17.05.0000.24042
- - diff --git a/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-std.html b/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-std.html deleted file mode 100644 index 8bcc9794e..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/timetable/PlanLekcji-std.html +++ /dev/null @@ -1,303 +0,0 @@ - - - - - Witryna ucznia i rodzica – Plan lekcji - - -
-

Plan lekcji

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
LekcjaPora lekcjiponiedziałek
19.06.2017
wtorek
20.06.2017
środa
21.06.2017
czwartek
22.06.2017
piątek
23.06.2017
108:00 08:45 -
- Edukacja dla bezpieczeństwa - Kobczyk Iwona - -
-
-
- Język niemiecki [JNPW] - - Dzwoniec Ewa - -
-
-
- Wychowanie do życia w rodzinie - Baran Dominika - -
-
-
- Język niemiecki [JNPW] - - Dzwoniec Ewa - -
-
208:50 09:35 -
- Historia - Bogatka Katarzyna - -
-
-
- Wychowanie fizyczne [CH] - - Brodziec Dominika - -
-
-
- Fizyka - Bocian Łukasz - -
-
-
- Biologia - Kowalska Anna - -
-
-
- Religia - Kraska Maciej - -
-
309:40 10:25 -
- Wychowanie fizyczne [CH] - - Brodziec Dominika - -
-
-
- Język polski - Rożeniec Paulina - -
-
-
- Matematyka - Bączek Dominika - -
-
-
- Plastyka - Rożeniec Paulina - -
-
-
- Zajęcia z wychowawcą - Kowalska Anna - -
-
410:30 11:15 -
- Geografia - Orłowski Konrad - -
-
-
- Matematyka - Bączek Dominika - -
-
-
- Język angielski [JAPN] - - Biegus Kazimiera - -
-
-
- Matematyka - Bączek Dominika - -
-
-
- Historia - Bogatka Katarzyna - -
-
511:30 12:15 -
- Matematyka - Bączek Dominika - -
-
-
- Biologia - Kowalska Anna - -
-
-
- Zajęcia techniczne - Chlebowski Stanisław - -
-
-
- Język angielski [JAPN] - - Biegus Kazimiera - -
-
-
- Język polski - Rożeniec Paulina - -
-
612:30 13:15 -
- Matematyka - Bączek Dominika - -
-
-
- Fizyka - Bocian Łukasz - -
-
-
- Język polski - Rożeniec Paulina - -
-
-
- Wychowanie fizyczne [CH] - - Brodziec Dominika - -
-
-
- Język polski - Rożeniec Paulina - -
-
713:20 14:05 -
- Język angielski [JAPN] - - Biegus Kazimiera - -
-
-
- Religia - Kraska Maciej - -
-
-
- Wychowanie fizyczne [CH] - - Brodziec Dominika - -
-
814:10 14:55
-
-
-
wersja: 17.02.0000.23328
- - diff --git a/api/src/test/resources/io/github/wulkanowy/api/user/UczenDanePodstawowe.html b/api/src/test/resources/io/github/wulkanowy/api/user/UczenDanePodstawowe.html deleted file mode 100644 index c54dd8614..000000000 --- a/api/src/test/resources/io/github/wulkanowy/api/user/UczenDanePodstawowe.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - Witryna ucznia i rodzica – Dane ucznia - - -
-

Dane podstawowe

-

Dane osobowe

-
-
- Imię (imiona) nazwisko: - Maria Aneta Kamińska -
-
- Data i miejsce urodzenia: - 01.01.1900, Warszawa -
-
- PESEL: - 12345678900 -
-
- Płeć: - Kobieta -
-
- Obywatelstwo polskie: - Tak -
-
- Nazwisko rodowe: - Nowak -
-
- Imię matki i ojca: - Gabriela, Kamil -
-
-

Dane adresowe

-
-
- Adres zamieszkania: - ul. Sportowa 16, 00-123 Warszawa -
-
- Adres zameldowania: - ul. Sportowa 17, 00-123 Warszawa -
-
- Adres korespondencji: - ul. Sportowa 18, 00-123 Warszawa -
-
-

Kontakt

-
-
- Telefon: - 005554433 -
-
- Telefon komórkowy: - 555444333 -
-
- E-mail: - wulkanowy@example.null -
-
-

Rodzina

-
-
- Nazwisko i imię: - Marianna Pająk -
-
- Stopień pokrewieństwa: - matka -
-
- Adres: - ul. Sportowa 16, 00-123 Warszawa -
-
- Telefony: - 555111222 -
-
- E-mail: - wulkanowy@example.null -
-
-
-
- Nazwisko i imię: - Dawid Świątek -
-
- Stopień pokrewieństwa: - ojciec -
-
- Adres: - ul. Sportowa 18, 00-123 Warszawa -
-
- Telefony: - 555222111 -
-
- E-mail: - wulkanowy@example.null -
-
-
-
wersja: 17.02.0000.23328
- - diff --git a/app/build.gradle b/app/build.gradle index 38b4c9472..9a870db5b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,31 +1,12 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' -apply plugin: 'kotlin-kapt'// sync warning probably caused by bug https://issuetracker.google.com/issues/74537216 +apply plugin: 'kotlin-kapt'// sync warning probably caused by bug https://issuetracker.google.com/issues/74537216, fix in AS 3.2 apply plugin: 'kotlin-android-extensions' apply plugin: 'io.fabric' apply from: 'jacoco.gradle' -apply from: 'android-sonarqube.gradle' -apply plugin: 'com.google.gms.oss.licenses.plugin' +apply from: 'sonarqube.gradle' apply plugin: 'com.github.triplet.play' -buildscript { - repositories { - maven { url "https://plugins.gradle.org/m2/" } - maven { url 'https://maven.fabric.io/public' } - google() - } - - dependencies { - classpath "io.fabric.tools:gradle:$fabricGradle" - classpath "com.google.gms:oss-licenses:0.9.2" - classpath "com.github.triplet.gradle:play-publisher:$playPublisher" - } -} - -repositories { - maven { url 'https://maven.fabric.io/public' } -} - android { compileSdkVersion 27 buildToolsVersion '27.0.3' @@ -76,16 +57,6 @@ android { multiDexKeepProguard file('proguard-multidex-rules.pro') } } - - testOptions { - unitTests.all { - testLogging { - events "passed", "skipped", "failed", "standardOut", "standardError" - outputs.upToDateWhen { false } - showStandardStreams = true - } - } - } } androidExtensions { @@ -97,54 +68,57 @@ play { uploadImages = true } -configurations.all { - resolutionStrategy.force "com.android.support:support-annotations:$supportVersion" -} +ext.supportVersion = "27.1.1" dependencies { - implementation project(':api') - implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" + implementation 'com.github.wulkanowy:api:88ede83149' + implementation "com.android.support:support-v4:$supportVersion" implementation "com.android.support:design:$supportVersion" implementation "com.android.support:cardview-v7:$supportVersion" implementation "com.android.support:preference-v14:$supportVersion" - implementation "com.firebase:firebase-jobdispatcher:$firebaseJob" - implementation "org.apache.commons:commons-lang3:$apacheLang" - implementation "org.apache.commons:commons-collections4:$apacheCollections" - implementation "eu.davidea:flexible-adapter:$flexibleAdapter" - implementation "eu.davidea:flexible-adapter-ui:$flexibleUi" - implementation "com.google.dagger:dagger-android-support:$dagger2" - implementation "com.aurelhubert:ahbottomnavigation:$ahbottom" - implementation "com.jakewharton.threetenabp:threetenabp:$threeTenABP" - implementation "com.google.android.gms:play-services-oss-licenses:$ossLicenses" - implementation "com.jakewharton.timber:timber:$timber" - implementation "at.favre.lib:slf4j-timber:$slf4jTimber" - implementation "android.arch.persistence.room:runtime:1.1.1" - implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' - implementation "io.reactivex.rxjava2:rxjava:2.2.0" implementation 'com.android.support:multidex:1.0.3' + + implementation "com.google.android.gms:play-services-oss-licenses:16.0.0" + implementation "com.firebase:firebase-jobdispatcher:0.8.5" + + implementation "com.google.dagger:dagger-android-support:2.17" + kapt "com.google.dagger:dagger-compiler:2.17" + kapt "com.google.dagger:dagger-android-processor:2.17" + + implementation "android.arch.persistence.room:runtime:1.1.1" implementation "android.arch.persistence.room:rxjava2:1.1.1" - implementation 'com.github.pwittchen:reactivenetwork-rx2:2.1.0' - implementation 'com.ncapdevi:frag-nav:3.0.0-RC3' - - implementation("com.crashlytics.sdk.android:crashlytics:$crashlyticsSdk@aar") { - transitive = true - } - implementation("com.crashlytics.sdk.android:answers:$crashlyticsAnswers@aar") { - transitive = true - } - - kapt "com.google.dagger:dagger-compiler:$dagger2" - kapt "com.google.dagger:dagger-android-processor:$dagger2" kapt "android.arch.persistence.room:compiler:1.1.1" - debugImplementation "com.amitshekhar.android:debug-db:$debugDb" + implementation "eu.davidea:flexible-adapter:5.0.5" + implementation "eu.davidea:flexible-adapter-ui:1.0.0-b5" + implementation "com.aurelhubert:ahbottomnavigation:2.2.0" + implementation 'com.ncapdevi:frag-nav:3.0.0-RC3' - testImplementation "junit:junit:$junit" - testImplementation "org.mockito:mockito-inline:$mockito" - testImplementation "org.jsoup:jsoup:$jsoup" + implementation 'com.github.pwittchen:reactivenetwork-rx2:2.1.0' + implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' + implementation "io.reactivex.rxjava2:rxjava:2.2.0" - androidTestImplementation "com.android.support.test:runner:$testRunner" - androidTestImplementation "org.mockito:mockito-android:$mockito" + implementation "org.apache.commons:commons-lang3:3.8" + implementation "org.apache.commons:commons-collections4:4.2" + implementation "com.jakewharton.threetenabp:threetenabp:1.1.0" + + implementation "com.jakewharton.timber:timber:4.7.1" + implementation "at.favre.lib:slf4j-timber:1.0.1" + implementation("com.crashlytics.sdk.android:crashlytics:2.9.5@aar") { + transitive = true + } + implementation("com.crashlytics.sdk.android:answers:1.4.3@aar") { + transitive = true + } + + debugImplementation "com.amitshekhar.android:debug-db:1.0.4" + + testImplementation "junit:junit:4.12" + testImplementation "org.mockito:mockito-inline:2.21.0" + + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation "org.mockito:mockito-android:2.21.0" androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version" } diff --git a/app/jacoco.gradle b/app/jacoco.gradle index 45c55617d..4f94ef190 100644 --- a/app/jacoco.gradle +++ b/app/jacoco.gradle @@ -1,7 +1,7 @@ apply plugin: "jacoco" jacoco { - toolVersion "0.8.1" + toolVersion "0.8.2" reportsDir = file("$buildDir/reports") } @@ -9,7 +9,6 @@ tasks.withType(Test) { jacoco.includeNoLocationClasses = true } -// run ./gradlew clean createDebugCoverageReport jacocoTestReport task jacocoTestReport(type: JacocoReport) { group = "Reporting" @@ -30,17 +29,12 @@ task jacocoTestReport(type: JacocoReport) { '**/*Dagger*.*', '**/*MembersInjector*.*', '**/*_Provide*Factory*.*', - '**/*_Factory.*', - '**/*$*$*.*' - ] + '**/*_Factory.*'] - // generated classes classDirectories = fileTree( - // Java generated classes on Android project (debug build) dir: "$buildDir/intermediates/classes/debug", excludes: excludes ) + fileTree( - // Kotlin generated classes on Android project (debug build) dir: "$buildDir/tmp/kotlin-classes/debug", excludes: excludes ) diff --git a/app/android-sonarqube.gradle b/app/sonarqube.gradle similarity index 80% rename from app/android-sonarqube.gradle rename to app/sonarqube.gradle index b9284eeac..9fd890d85 100644 --- a/app/android-sonarqube.gradle +++ b/app/sonarqube.gradle @@ -4,16 +4,13 @@ sonarqube { //noinspection GroovyAssignabilityCheck properties { - def files = fileTree("${rootProject.projectDir}/api/build/libs/").filter { it.isFile() }.files.name - def libraries = project.android.sdkDirectory.getPath() + "/platforms/android-27/android.jar," + - "${project.rootDir}/api/build/libs/" + files[0] + def libraries = project.android.sdkDirectory.getPath() + "/platforms/android-27/android.jar" property "sonar.projectName", GROUP_ID + ":app" property "sonar.projectKey", GROUP_ID + ":app" property "sonar.sources", "src/main/java" - property "sonar.exclusions", "build/**,**/*.png,*.iml, **/*generated*," + - "src/**/entities/*.java, src/androidTest/**/entities/*.java" + property "sonar.exclusions", "build/**,**/*.png,*.iml, **/*generated*," property "sonar.import_unknown_files", true // Defines where the java files are diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/StudentLocalTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/StudentLocalTest.kt index e4e9e1dfd..7103d478b 100644 --- a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/StudentLocalTest.kt +++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/StudentLocalTest.kt @@ -38,7 +38,7 @@ class StudentLocalTest { @Test fun saveAndReadTest() { - studentLocal.save(Student(email = "test", password = "test123", schoolId = "23")) + studentLocal.save(Student(email = "test", password = "test123", schoolId = "23")).blockingAwait() assert(sharedHelper.getLong(StudentLocal.CURRENT_USER_KEY, 0) == 1L) assert(studentLocal.isStudentLoggedIn) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a4c2c9471..47e6e013e 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -28,13 +28,13 @@ + android:resource="@xml/provider_widget_timetable" /> - diff --git a/app/src/main/java/io/github/wulkanowy/data/ErrorHandler.kt b/app/src/main/java/io/github/wulkanowy/data/ErrorHandler.kt index 207e9251f..67edf916d 100644 --- a/app/src/main/java/io/github/wulkanowy/data/ErrorHandler.kt +++ b/app/src/main/java/io/github/wulkanowy/data/ErrorHandler.kt @@ -2,7 +2,7 @@ package io.github.wulkanowy.data import android.content.res.Resources import io.github.wulkanowy.R -import io.github.wulkanowy.api.NotLoggedInErrorException +import io.github.wulkanowy.api.auth.NotLoggedInException import timber.log.Timber import java.io.IOException import java.net.SocketTimeoutException @@ -17,9 +17,9 @@ open class ErrorHandler @Inject constructor(private val resources: Resources) { Timber.i(error, "An exception occurred while the Wulkanowy was running") showErrorMessage((when (error) { - is UnknownHostException -> resources.getString(R.string.noInternet_text) - is SocketTimeoutException -> resources.getString(R.string.generic_timeout_error) - is NotLoggedInErrorException, is IOException -> resources.getString(R.string.login_failed_text) + is UnknownHostException -> resources.getString(R.string.all_no_internet) + is SocketTimeoutException -> resources.getString(R.string.all_timeout) + is NotLoggedInException, is IOException -> resources.getString(R.string.all_login_failed) else -> error.localizedMessage })) } @@ -28,4 +28,3 @@ open class ErrorHandler @Inject constructor(private val resources: Resources) { showErrorMessage = {} } } - diff --git a/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt b/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt index 6cacc01e5..5cca9bd15 100644 --- a/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt +++ b/app/src/main/java/io/github/wulkanowy/data/RepositoryModule.kt @@ -7,7 +7,7 @@ import android.support.v7.preference.PreferenceManager import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings import dagger.Module import dagger.Provides -import io.github.wulkanowy.api.Vulcan +import io.github.wulkanowy.api.Api import io.github.wulkanowy.data.db.AppDatabase import io.github.wulkanowy.utils.DATABASE_NAME import javax.inject.Singleton @@ -23,7 +23,7 @@ internal class RepositoryModule { @Singleton @Provides - fun provideVulcanApi() = Vulcan() + fun provideApi() = Api() @Singleton @Provides @@ -41,4 +41,4 @@ internal class RepositoryModule { @Singleton @Provides fun provideStudentDao(database: AppDatabase) = database.studentDao() -} \ No newline at end of file +} diff --git a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt index ffb02591b..c140cf0bc 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/AppDatabase.kt @@ -2,17 +2,21 @@ package io.github.wulkanowy.data.db import android.arch.persistence.room.Database import android.arch.persistence.room.RoomDatabase +import io.github.wulkanowy.data.db.dao.SemesterDao import io.github.wulkanowy.data.db.dao.StudentDao +import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Student import javax.inject.Singleton @Singleton @Database( - entities = [Student::class], + entities = [Student::class, Semester::class], version = 1, exportSchema = false ) abstract class AppDatabase : RoomDatabase() { abstract fun studentDao(): StudentDao -} \ No newline at end of file + + abstract fun semesterDao(): SemesterDao +} diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/SemesterDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/SemesterDao.kt new file mode 100644 index 000000000..a8ebb4788 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/SemesterDao.kt @@ -0,0 +1,13 @@ +package io.github.wulkanowy.data.db.dao + +import android.arch.persistence.room.Dao +import android.arch.persistence.room.Insert +import android.arch.persistence.room.OnConflictStrategy.REPLACE +import io.github.wulkanowy.data.db.entities.Semester + +@Dao +interface SemesterDao { + + @Insert(onConflict = REPLACE) + fun insert(semester: Semester): Long +} diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Semester.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Semester.kt new file mode 100644 index 000000000..dec731d7a --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Semester.kt @@ -0,0 +1,26 @@ +package io.github.wulkanowy.data.db.entities + +import android.arch.persistence.room.ColumnInfo +import android.arch.persistence.room.Entity +import android.arch.persistence.room.Index +import android.arch.persistence.room.PrimaryKey + +@Entity(tableName = "Semesters", + indices = [Index(value = ["diary_id", "semester_id"], unique = true)]) +data class Semester( + + @PrimaryKey + var id: Long = 0, + + @ColumnInfo(name = "diary_id") + var diaryId: String, + + @ColumnInfo(name = "diary_name") + var diaryName: String = "", + + @ColumnInfo(name = "semester_id") + var semesterId: String, + + @ColumnInfo(name = "semester_name") + var semesterName: String = "" +) diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt index 59659ea54..316c482c3 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt @@ -5,6 +5,7 @@ import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.Inter import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.repositories.local.StudentLocal import io.github.wulkanowy.data.repositories.remote.StudentRemote +import io.reactivex.Completable import io.reactivex.Single import java.net.UnknownHostException import javax.inject.Inject @@ -31,9 +32,7 @@ class StudentRepository @Inject constructor( return cachedStudents } - fun save(student: Student) { - local.save(student) - } + fun save(student: Student): Completable = local.save(student) fun getCurrentStudent(): Single = local.getCurrentStudent() diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/local/StudentLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/local/StudentLocal.kt index 6c325f68e..a500141c3 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/local/StudentLocal.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/local/StudentLocal.kt @@ -6,6 +6,7 @@ import io.github.wulkanowy.data.db.dao.StudentDao import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.utils.security.Scrambler.decrypt import io.github.wulkanowy.utils.security.Scrambler.encrypt +import io.reactivex.Completable import io.reactivex.Single import javax.inject.Inject import javax.inject.Singleton @@ -23,9 +24,10 @@ class StudentLocal @Inject constructor( val isStudentLoggedIn: Boolean get() = sharedPref.getLong(CURRENT_USER_KEY, 0) != 0L - fun save(student: Student) { - sharedPref.putLong(CURRENT_USER_KEY, studentDb.insert(student.copy( - password = encrypt(student.password, context)))) + fun save(student: Student): Completable { + return Single.fromCallable { studentDb.insert(student.copy(password = encrypt(student.password, context))) } + .map { sharedPref.putLong(CURRENT_USER_KEY, it) } + .ignoreElement() } fun getCurrentStudent(): Single { diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/StudentRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/remote/StudentRemote.kt index 491c3fdd9..02b447232 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/StudentRemote.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/remote/StudentRemote.kt @@ -1,55 +1,32 @@ package io.github.wulkanowy.data.repositories.remote -import io.github.wulkanowy.api.Vulcan -import io.github.wulkanowy.api.login.AccountPermissionException +import io.github.wulkanowy.api.Api import io.github.wulkanowy.data.db.entities.Student -import io.github.wulkanowy.utils.DEFAULT_SYMBOL import io.reactivex.Single -import org.apache.commons.lang3.StringUtils.stripAccents import javax.inject.Inject import javax.inject.Singleton @Singleton -class StudentRemote @Inject constructor(private val api: Vulcan) { +class StudentRemote @Inject constructor(private val api: Api) { fun getConnectedStudents(email: String, password: String, symbol: String): Single> { - return Single.fromCallable { - initApi(email, password, symbol) - getSymbols().filterNot { it == DEFAULT_SYMBOL } - .mapNotNull { symbol -> - try { - initApi(email, password, symbol) - api.schools.flatMap { school -> - initApi(email, password, symbol, school.id) - api.studentAndParent.students.map { student -> - Student( - email = email, - password = password, - symbol = symbol, - studentId = student.id, - studentName = student.name, - schoolId = school.id, - schoolName = school.name - ) - } - } - } catch (e: AccountPermissionException) { - null - } - }.flatten() + api.let { + it.email = email + it.password = password + it.symbol = symbol + it.host = "vulcan.net.pl" + it.onConfigChange() } - } - - private fun initApi(email: String, password: String, symbol: String, schoolId: String? = null) { - api.apply { - logout() - setCredentials(email, password, symbol, schoolId, null, null) - } - } - - private fun getSymbols(): List { - return api.symbols.map { - stripAccents(it.replace("[\\s \\W]".toRegex(), "")) + return api.getPupils().map { students -> + students.map { + Student(email = email, + password = password, + symbol = it.symbol, + studentId = it.studentId, + studentName = it.studentName, + schoolId = it.schoolId, + schoolName = it.schoolName) + } } } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BaseActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/base/BaseActivity.kt index 696834e08..0946b251d 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/BaseActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/base/BaseActivity.kt @@ -23,7 +23,7 @@ abstract class BaseActivity : DaggerAppCompatActivity(), BaseView { } override fun showNoNetworkMessage() { - showMessage(getString(R.string.noInternet_text)) + showMessage(getString(R.string.all_no_internet)) } override fun onDestroy() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginErrorHandler.kt b/app/src/main/java/io/github/wulkanowy/ui/login/LoginErrorHandler.kt index 93b66ab18..5eeaceb7e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginErrorHandler.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginErrorHandler.kt @@ -1,7 +1,7 @@ package io.github.wulkanowy.ui.login import android.content.res.Resources -import io.github.wulkanowy.api.login.BadCredentialsException +import io.github.wulkanowy.api.auth.BadCredentialsException import io.github.wulkanowy.data.ErrorHandler class LoginErrorHandler(resources: Resources) : ErrorHandler(resources) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/form/LoginFormFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/login/form/LoginFormFragment.kt index cf231c3e1..b2e3145bc 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/form/LoginFormFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/login/form/LoginFormFragment.kt @@ -54,7 +54,7 @@ class LoginFormFragment : BaseFragment(), LoginFormView { } override fun showSymbolInput() { - loginHeader.text = getString(R.string.login_heading_symbol) + loginHeader.text = getString(R.string.login_header_symbol) loginMainForm.visibility = GONE loginSymbolInput.visibility = VISIBLE loginSymbolEdit.requestFocus() @@ -68,49 +68,49 @@ class LoginFormFragment : BaseFragment(), LoginFormView { override fun setErrorEmailRequired() { loginEmailEdit.run { requestFocus() - error = getString(R.string.error_field_required) + error = getString(R.string.login_field_required) } } override fun setErrorEmailInvalid() { loginEmailEdit.run { requestFocus() - error = getString(R.string.error_invalid_email) + error = getString(R.string.login_invalid_email) } } override fun setErrorPassRequired(focus: Boolean) { loginPassEdit.run { if (focus) requestFocus() - error = getString(R.string.error_field_required) + error = getString(R.string.login_field_required) } } override fun setErrorPassInvalid(focus: Boolean) { loginPassEdit.run { if (focus) requestFocus() - error = getString(R.string.error_invalid_password) + error = getString(R.string.login_invalid_password) } } override fun setErrorSymbolRequire() { loginSymbolEdit.run { requestFocus() - error = getString(R.string.error_field_required) + error = getString(R.string.login_field_required) } } override fun setErrorPassIncorrect() { loginPassEdit.run { requestFocus() - error = getString(R.string.error_incorrect_password) + error = getString(R.string.login_incorrect_password) } } override fun setErrorSymbolIncorrect() { loginSymbolEdit.run { requestFocus() - error = getString(R.string.error_incorrect_symbol) + error = getString(R.string.login_incorrect_symbol) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/options/LoginOptionsItem.kt b/app/src/main/java/io/github/wulkanowy/ui/login/options/LoginOptionsItem.kt index 777c7ef4c..5abab9bc8 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/options/LoginOptionsItem.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/login/options/LoginOptionsItem.kt @@ -8,11 +8,11 @@ import eu.davidea.viewholders.FlexibleViewHolder import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Student import kotlinx.android.extensions.LayoutContainer -import kotlinx.android.synthetic.main.fragment_login_opions_item.view.* +import kotlinx.android.synthetic.main.item_login_options.view.* class LoginOptionsItem(val student: Student) : AbstractFlexibleItem() { - override fun getLayoutRes(): Int = R.layout.fragment_login_opions_item + override fun getLayoutRes(): Int = R.layout.item_login_options override fun createViewHolder(view: View?, adapter: FlexibleAdapter>?): ItemViewHolder { return ItemViewHolder(view, adapter) diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/options/LoginOptionsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/login/options/LoginOptionsPresenter.kt index f714596d2..3221cf51a 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/options/LoginOptionsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/login/options/LoginOptionsPresenter.kt @@ -5,7 +5,6 @@ import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.repositories.StudentRepository import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.utils.schedulers.SchedulersManager -import io.reactivex.Single import javax.inject.Inject class LoginOptionsPresenter @Inject constructor( @@ -33,16 +32,13 @@ class LoginOptionsPresenter @Inject constructor( } fun onSelectStudent(student: Student) { - disposable.add(student.let { - Single.fromCallable { repository.save(it) } - .subscribeOn(schedulers.backgroundThread()) - .observeOn(schedulers.mainThread()) - .doOnSubscribe { _ -> - view?.showLoginProgress(true) - view?.showActionBar(false) - } - .doOnSuccess { _ -> view?.openMainView() } - .subscribe({ _ -> }, { error -> errorHandler.proceed(error) }) - }) + disposable.add(repository.save(student) + .subscribeOn(schedulers.backgroundThread()) + .observeOn(schedulers.mainThread()) + .doOnSubscribe { _ -> + view?.showLoginProgress(true) + view?.showActionBar(false) + } + .subscribe({ view?.openMainView() }, { errorHandler.proceed(it) })) } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.kt index 5b8450804..4ec418fb3 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/MainActivity.kt @@ -58,11 +58,11 @@ class MainActivity : BaseActivity(), MainView, FragNavController.TransactionList override fun initBottomNav() { mainBottomNav.run { addItems(mutableListOf( - AHBottomNavigationItem(R.string.grades_text, R.drawable.ic_menu_grade_26dp, 0), - AHBottomNavigationItem(R.string.attendance_text, R.drawable.ic_menu_attendance_24dp, 0), - AHBottomNavigationItem(R.string.exams_text, R.drawable.ic_menu_exams_24dp, 0), - AHBottomNavigationItem(R.string.timetable_text, R.drawable.ic_menu_timetable_24dp, 0), - AHBottomNavigationItem(R.string.more_text, R.drawable.ic_menu_other_24dp, 0) + AHBottomNavigationItem(R.string.grade_title, R.drawable.ic_menu_main_grade_26dp, 0), + AHBottomNavigationItem(R.string.attendance_title, R.drawable.ic_menu_main_attendance_24dp, 0), + AHBottomNavigationItem(R.string.exam_title, R.drawable.ic_menu_main_exam_24dp, 0), + AHBottomNavigationItem(R.string.timetable_title, R.drawable.ic_menu_main_timetable_24dp, 0), + AHBottomNavigationItem(R.string.more_title, R.drawable.ic_menu_main_more_24dp, 0) )) accentColor = ContextCompat.getColor(context, R.color.colorPrimary) inactiveColor = ContextCompat.getColor(context, android.R.color.black) @@ -89,14 +89,14 @@ class MainActivity : BaseActivity(), MainView, FragNavController.TransactionList setTitle(title) } - override fun defaultTitle(): String = getString(R.string.activity_main_text) + override fun defaultTitle(): String = getString(R.string.main_title) override fun mapOfTitles(): Map { - return mapOf(0 to R.string.grades_text, - 1 to R.string.attendance_text, - 2 to R.string.exams_text, - 3 to R.string.timetable_text, - 4 to R.string.more_text + return mapOf(0 to R.string.grade_title, + 1 to R.string.attendance_title, + 2 to R.string.exam_title, + 3 to R.string.timetable_title, + 4 to R.string.more_title ).mapValues { getString(it.value) } } @@ -105,4 +105,3 @@ class MainActivity : BaseActivity(), MainView, FragNavController.TransactionList navController.onSaveInstanceState(outState) } } - diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamFragment.kt index 6e8ad5998..ca60fe888 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamFragment.kt @@ -14,7 +14,6 @@ class ExamFragment : BaseFragment() { } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_exams, container, false) + return inflater.inflate(R.layout.fragment_exam, container, false) } } - diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/grade/GradeFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/main/grade/GradeFragment.kt index 3b70cdbc2..961afb1e0 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/grade/GradeFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/grade/GradeFragment.kt @@ -14,7 +14,6 @@ class GradeFragment : BaseFragment() { } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - return inflater.inflate(R.layout.fragment_grades, container, false) + return inflater.inflate(R.layout.fragment_grade, container, false) } } - diff --git a/app/src/main/java/io/github/wulkanowy/utils/CommonUtils.java b/app/src/main/java/io/github/wulkanowy/utils/CommonUtils.java index 5c94cc57a..d84770e54 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/CommonUtils.java +++ b/app/src/main/java/io/github/wulkanowy/utils/CommonUtils.java @@ -16,19 +16,19 @@ public final class CommonUtils { public static int colorHexToColorName(String hexColor) { switch (hexColor) { case "000000": - return R.string.color_black_text; + return R.string.all_black; case "F04C4C": - return R.string.color_red_text; + return R.string.all_red; case "20A4F7": - return R.string.color_blue_text; + return R.string.all_blue; case "6ECD07": - return R.string.color_green_text; + return R.string.all_green; default: - return R.string.noColor_text; + return R.string.all_empty_color; } } diff --git a/app/src/main/res/drawable-hdpi/ic_notify_grade.png b/app/src/main/res/drawable-hdpi/ic_stat_notify_grade.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_notify_grade.png rename to app/src/main/res/drawable-hdpi/ic_stat_notify_grade.png diff --git a/app/src/main/res/drawable-mdpi/ic_notify_grade.png b/app/src/main/res/drawable-mdpi/ic_stat_notify_grade.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_notify_grade.png rename to app/src/main/res/drawable-mdpi/ic_stat_notify_grade.png diff --git a/app/src/main/res/drawable-night/ic_border.xml b/app/src/main/res/drawable-night/ic_all_divider.xml similarity index 100% rename from app/src/main/res/drawable-night/ic_border.xml rename to app/src/main/res/drawable-night/ic_all_divider.xml diff --git a/app/src/main/res/drawable-v15/splash_background.xml b/app/src/main/res/drawable-v15/splash_background.xml deleted file mode 100644 index c58c374a1..000000000 --- a/app/src/main/res/drawable-v15/splash_background.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - diff --git a/app/src/main/res/drawable-v23/splash_background.xml b/app/src/main/res/drawable-v23/splash_background.xml deleted file mode 100644 index 611bb2a7a..000000000 --- a/app/src/main/res/drawable-v23/splash_background.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - diff --git a/app/src/main/res/drawable-xhdpi/ic_notify_grade.png b/app/src/main/res/drawable-xhdpi/ic_stat_notify_grade.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_notify_grade.png rename to app/src/main/res/drawable-xhdpi/ic_stat_notify_grade.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_notify_grade.png b/app/src/main/res/drawable-xxhdpi/ic_stat_notify_grade.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_notify_grade.png rename to app/src/main/res/drawable-xxhdpi/ic_stat_notify_grade.png diff --git a/app/src/main/res/drawable/ic_border.xml b/app/src/main/res/drawable/ic_all_divider.xml similarity index 100% rename from app/src/main/res/drawable/ic_border.xml rename to app/src/main/res/drawable/ic_all_divider.xml diff --git a/app/src/main/res/drawable/ic_exclamation_24dp.xml b/app/src/main/res/drawable/ic_all_note_24dp.xml similarity index 96% rename from app/src/main/res/drawable/ic_exclamation_24dp.xml rename to app/src/main/res/drawable/ic_all_note_24dp.xml index 149504585..988df22c0 100644 --- a/app/src/main/res/drawable/ic_exclamation_24dp.xml +++ b/app/src/main/res/drawable/ic_all_note_24dp.xml @@ -7,4 +7,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/drawable/ic_alert_24dp.xml b/app/src/main/res/drawable/ic_all_round_note_24dp.xml similarity index 97% rename from app/src/main/res/drawable/ic_alert_24dp.xml rename to app/src/main/res/drawable/ic_all_round_note_24dp.xml index 1c41b556d..f4f1f2c52 100644 --- a/app/src/main/res/drawable/ic_alert_24dp.xml +++ b/app/src/main/res/drawable/ic_all_round_note_24dp.xml @@ -7,4 +7,4 @@ android:fillColor="@color/colorPrimary" android:pathData="M13 13h-2V7h2m0 10h-2v-2h2M12 2A10 10 0 0 0 2 12a10 10 0 0 0 10 10 10 10 0 0 0 10-10A10 10 0 0 0 12 2z" /> - \ No newline at end of file + diff --git a/app/src/main/res/drawable/ic_action_menu_semester.xml b/app/src/main/res/drawable/ic_menu_grade_semester_24dp.xml similarity index 100% rename from app/src/main/res/drawable/ic_action_menu_semester.xml rename to app/src/main/res/drawable/ic_menu_grade_semester_24dp.xml diff --git a/app/src/main/res/drawable/ic_action_menu_summary.xml b/app/src/main/res/drawable/ic_menu_grade_summary_24dp.xml similarity index 100% rename from app/src/main/res/drawable/ic_action_menu_summary.xml rename to app/src/main/res/drawable/ic_menu_grade_summary_24dp.xml diff --git a/app/src/main/res/drawable/ic_menu_attendance_24dp.xml b/app/src/main/res/drawable/ic_menu_main_attendance_24dp.xml similarity index 100% rename from app/src/main/res/drawable/ic_menu_attendance_24dp.xml rename to app/src/main/res/drawable/ic_menu_main_attendance_24dp.xml diff --git a/app/src/main/res/drawable/ic_menu_exams_24dp.xml b/app/src/main/res/drawable/ic_menu_main_exam_24dp.xml similarity index 100% rename from app/src/main/res/drawable/ic_menu_exams_24dp.xml rename to app/src/main/res/drawable/ic_menu_main_exam_24dp.xml diff --git a/app/src/main/res/drawable/ic_menu_grade_26dp.xml b/app/src/main/res/drawable/ic_menu_main_grade_26dp.xml similarity index 100% rename from app/src/main/res/drawable/ic_menu_grade_26dp.xml rename to app/src/main/res/drawable/ic_menu_main_grade_26dp.xml diff --git a/app/src/main/res/drawable/ic_menu_main_more_24dp.xml b/app/src/main/res/drawable/ic_menu_main_more_24dp.xml new file mode 100644 index 000000000..26932b2b2 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu_main_more_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_menu_timetable_24dp.xml b/app/src/main/res/drawable/ic_menu_main_timetable_24dp.xml similarity index 100% rename from app/src/main/res/drawable/ic_menu_timetable_24dp.xml rename to app/src/main/res/drawable/ic_menu_main_timetable_24dp.xml diff --git a/app/src/main/res/drawable/ic_menu_other_24dp.xml b/app/src/main/res/drawable/ic_menu_other_24dp.xml deleted file mode 100644 index a07747245..000000000 --- a/app/src/main/res/drawable/ic_menu_other_24dp.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_swap_30dp.xml b/app/src/main/res/drawable/ic_timetable_swap_30dp.xml similarity index 100% rename from app/src/main/res/drawable/ic_swap_30dp.xml rename to app/src/main/res/drawable/ic_timetable_swap_30dp.xml diff --git a/app/src/main/res/drawable/img_splash_512px.png b/app/src/main/res/drawable/img_splash_512px.png deleted file mode 100644 index 9d8f403c2885d82a1d4c0c0f19d083c3880ce75a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9691 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 ypwT=unukX7&}bfdFq#Ocm + + + + diff --git a/app/src/main/res/drawable/splash_background.xml b/app/src/main/res/drawable/splash_background.xml deleted file mode 100644 index 0b79b6729..000000000 --- a/app/src/main/res/drawable/splash_background.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index 35a681f0a..3b04cf220 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -7,5 +7,4 @@ android:id="@+id/loginViewpager" android:layout_width="match_parent" android:layout_height="match_parent" /> - - \ No newline at end of file + diff --git a/app/src/main/res/layout/current_week_tab.xml b/app/src/main/res/layout/current_week_tab.xml deleted file mode 100644 index ab3755a12..000000000 --- a/app/src/main/res/layout/current_week_tab.xml +++ /dev/null @@ -1,8 +0,0 @@ - - diff --git a/app/src/main/res/layout/attendance_dialog.xml b/app/src/main/res/layout/dialog_attendance.xml similarity index 91% rename from app/src/main/res/layout/attendance_dialog.xml rename to app/src/main/res/layout/dialog_attendance.xml index 4b0f1ff9a..730b632d7 100644 --- a/app/src/main/res/layout/attendance_dialog.xml +++ b/app/src/main/res/layout/dialog_attendance.xml @@ -35,7 +35,7 @@ android:minHeight="60dp" android:minLines="2" android:paddingTop="10dp" - android:text="@string/generic_dialog_details" + android:text="@string/all_details" android:textIsSelectable="true" android:textSize="20sp" /> @@ -47,7 +47,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/attendance_dialog_details" android:layout_marginTop="10dp" - android:text="@string/attendance_dialog_subject" + android:text="@string/all_subject" android:textIsSelectable="true" android:textSize="17sp" /> @@ -59,7 +59,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/attendance_dialog_subject" android:layout_marginTop="3dp" - android:text="@string/generic_app_no_data" + android:text="@string/all_no_data" android:textIsSelectable="true" android:textSize="12sp" /> @@ -71,7 +71,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/attendance_dialog_subject_value" android:layout_marginTop="10dp" - android:text="@string/attendance_dialog_description" + android:text="@string/all_description" android:textSize="17sp" /> @@ -94,7 +94,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/attendance_dialog_description_value" android:layout_marginTop="10dp" - android:text="@string/attendance_dialog_date" + android:text="@string/all_date" android:textSize="17sp" /> @@ -117,7 +117,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/attendance_dialog_date_value" android:layout_marginTop="10dp" - android:text="@string/attendance_dialog_number" + android:text="@string/attendance_number" android:textSize="17sp" /> @@ -143,9 +143,9 @@ android:layout_marginTop="25dp" android:background="?attr/selectableItemBackground" android:focusable="true" - android:text="@string/generic_dialog_close" - android:textColor="?android:attr/android:textColorSecondary" + android:text="@string/all_close" android:textAllCaps="true" + android:textColor="?android:attr/android:textColorSecondary" android:textSize="15sp" /> diff --git a/app/src/main/res/layout/exams_dialog.xml b/app/src/main/res/layout/dialog_exam.xml similarity index 90% rename from app/src/main/res/layout/exams_dialog.xml rename to app/src/main/res/layout/dialog_exam.xml index 72d4b8ddb..e59956ef8 100644 --- a/app/src/main/res/layout/exams_dialog.xml +++ b/app/src/main/res/layout/dialog_exam.xml @@ -35,7 +35,7 @@ android:minHeight="60dp" android:minLines="2" android:paddingTop="10dp" - android:text="@string/generic_dialog_details" + android:text="@string/all_details" android:textIsSelectable="true" android:textSize="20sp" /> @@ -47,7 +47,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/exams_dialog_details" android:layout_marginTop="10dp" - android:text="@string/attendance_dialog_subject" + android:text="@string/all_subject" android:textIsSelectable="true" android:textSize="17sp" /> @@ -59,7 +59,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/exams_dialog_subject" android:layout_marginTop="3dp" - android:text="@string/generic_app_no_data" + android:text="@string/all_no_data" android:textIsSelectable="true" android:textSize="12sp" /> @@ -71,7 +71,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/exams_dialog_subject_value" android:layout_marginTop="10dp" - android:text="@string/exams_type" + android:text="@string/exam_type" android:textIsSelectable="true" android:textSize="17sp" /> @@ -83,7 +83,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/exams_dialog_type" android:layout_marginTop="3dp" - android:text="@string/generic_app_no_data" + android:text="@string/all_no_data" android:textIsSelectable="true" android:textSize="12sp" /> @@ -95,7 +95,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/exams_dialog_type_value" android:layout_marginTop="10dp" - android:text="@string/generic_dialog_teacher" + android:text="@string/all_teacher" android:textSize="17sp" /> @@ -118,7 +118,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/exams_dialog_teacher_value" android:layout_marginTop="10dp" - android:text="@string/exams_dialog_entry_date" + android:text="@string/exam_entry_date" android:textSize="17sp" /> @@ -141,7 +141,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/exams_dialog_date_value" android:layout_marginTop="10dp" - android:text="@string/dialog_description_text" + android:text="@string/all_description" android:textSize="17sp" /> @@ -168,7 +168,7 @@ android:layout_marginTop="25dp" android:background="?attr/selectableItemBackground" android:focusable="true" - android:text="@string/generic_dialog_close" + android:text="@string/all_close" android:textColor="?android:attr/android:textColorSecondary" android:textAllCaps="true" android:textSize="15sp" /> diff --git a/app/src/main/res/layout/grades_dialog.xml b/app/src/main/res/layout/dialog_grade.xml similarity index 91% rename from app/src/main/res/layout/grades_dialog.xml rename to app/src/main/res/layout/dialog_grade.xml index 932c895ea..3f6943519 100644 --- a/app/src/main/res/layout/grades_dialog.xml +++ b/app/src/main/res/layout/dialog_grade.xml @@ -48,7 +48,7 @@ android:maxLines="5" android:minHeight="80dp" android:minLines="2" - android:text="@string/grades_text" + android:text="@string/grade_header" android:textIsSelectable="true" android:textSize="20sp" /> @@ -59,7 +59,7 @@ android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_below="@+id/grade_dialog_subject" - android:text="@string/dialog_description_text" + android:text="@string/all_description" android:textIsSelectable="true" android:textSize="17sp" /> @@ -71,7 +71,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/grade_dialog_description" android:layout_marginTop="3dp" - android:text="@string/noDescription_text" + android:text="@string/all_no_description" android:textIsSelectable="true" android:textSize="12sp" /> @@ -83,7 +83,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/grade_dialog_description_value" android:layout_marginTop="10dp" - android:text="@string/grade_weight_text" + android:text="@string/grade_weight" android:textSize="17sp" /> @@ -106,7 +106,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/grade_dialog_weight_value" android:layout_marginTop="10dp" - android:text="@string/dialog_teacher_text" + android:text="@string/all_teacher" android:textSize="17sp" /> @@ -129,7 +129,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/grade_dialog_teacher_value" android:layout_marginTop="10dp" - android:text="@string/dialog_color_text" + android:text="@string/all_color" android:textSize="17sp" /> @@ -152,7 +152,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/grade_dialog_color_value" android:layout_marginTop="10dp" - android:text="@string/dialog_date_text" + android:text="@string/all_date" android:textSize="17sp" /> @@ -178,7 +178,7 @@ android:layout_marginTop="25dp" android:background="?attr/selectableItemBackground" android:focusable="true" - android:text="@string/generic_dialog_close" + android:text="@string/all_close" android:textColor="?android:attr/android:textColorSecondary" android:textAllCaps="true" android:textSize="15sp" /> diff --git a/app/src/main/res/layout/timetable_dialog.xml b/app/src/main/res/layout/dialog_timetable.xml similarity index 90% rename from app/src/main/res/layout/timetable_dialog.xml rename to app/src/main/res/layout/dialog_timetable.xml index 5898bc4a9..365af4bfe 100644 --- a/app/src/main/res/layout/timetable_dialog.xml +++ b/app/src/main/res/layout/dialog_timetable.xml @@ -35,7 +35,7 @@ android:minHeight="60dp" android:minLines="2" android:paddingTop="10dp" - android:text="@string/generic_dialog_details" + android:text="@string/all_details" android:textIsSelectable="true" android:textSize="20sp" /> @@ -47,7 +47,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/timetable_dialog_details" android:layout_marginTop="10dp" - android:text="@string/timetable_dialog_description" + android:text="@string/timetable_changes" android:textColor="@color/colorPrimary" android:textSize="17sp" /> @@ -59,7 +59,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/timetable_dialog_description" android:layout_marginTop="3dp" - android:text="@string/generic_app_no_data" + android:text="@string/all_no_data" android:textColor="@color/colorPrimary" android:textIsSelectable="true" android:textSize="12sp" /> @@ -72,7 +72,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/timetable_dialog_description_value" android:layout_marginTop="10dp" - android:text="@string/timetable_dialog_lesson" + android:text="@string/timetable_lesson" android:textIsSelectable="true" android:textSize="17sp" /> @@ -84,7 +84,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/timetable_dialog_lesson" android:layout_marginTop="3dp" - android:text="@string/generic_app_no_data" + android:text="@string/all_no_data" android:textIsSelectable="true" android:textSize="12sp" /> @@ -96,7 +96,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/timetable_dialog_lesson_value" android:layout_marginTop="10dp" - android:text="@string/generic_dialog_teacher" + android:text="@string/all_teacher" android:textSize="17sp" /> @@ -119,7 +119,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/timetable_dialog_teacher_value" android:layout_marginTop="10dp" - android:text="@string/timetable_dialog_group" + android:text="@string/timetable_group" android:textSize="17sp" /> @@ -142,7 +142,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/timetable_dialog_group_value" android:layout_marginTop="10dp" - android:text="@string/timetable_dialog_room" + android:text="@string/timetable_room" android:textSize="17sp" /> @@ -165,7 +165,7 @@ android:layout_alignParentStart="true" android:layout_below="@+id/timetable_dialog_room_value" android:layout_marginTop="10dp" - android:text="@string/timetable_dialog_time" + android:text="@string/timetable_time" android:textSize="17sp" /> @@ -191,7 +191,7 @@ android:layout_marginTop="25dp" android:background="?attr/selectableItemBackground" android:focusable="true" - android:text="@string/generic_dialog_close" + android:text="@string/all_close" android:textColor="?android:attr/android:textColorSecondary" android:textAllCaps="true" android:textSize="15sp" /> diff --git a/app/src/main/res/layout/fragment_attendance_tab.xml b/app/src/main/res/layout/fragment_attendance_tab.xml index 4dc450b58..38fc1bd72 100644 --- a/app/src/main/res/layout/fragment_attendance_tab.xml +++ b/app/src/main/res/layout/fragment_attendance_tab.xml @@ -35,7 +35,7 @@ android:minHeight="100dp" android:minWidth="100dp" app:tint="?android:attr/textColorPrimary" - app:srcCompat="@drawable/ic_menu_attendance_24dp" + app:srcCompat="@drawable/ic_menu_main_attendance_24dp" tools:ignore="contentDescription" /> diff --git a/app/src/main/res/layout/fragment_exams.xml b/app/src/main/res/layout/fragment_exam.xml similarity index 100% rename from app/src/main/res/layout/fragment_exams.xml rename to app/src/main/res/layout/fragment_exam.xml diff --git a/app/src/main/res/layout/fragment_exams_tab.xml b/app/src/main/res/layout/fragment_exam_tab.xml similarity index 95% rename from app/src/main/res/layout/fragment_exams_tab.xml rename to app/src/main/res/layout/fragment_exam_tab.xml index 433f5b1cb..9614f80fa 100644 --- a/app/src/main/res/layout/fragment_exams_tab.xml +++ b/app/src/main/res/layout/fragment_exam_tab.xml @@ -34,7 +34,7 @@ android:layout_marginTop="40dp" android:minHeight="100dp" android:minWidth="100dp" - app:srcCompat="@drawable/ic_menu_exams_24dp" + app:srcCompat="@drawable/ic_menu_main_exam_24dp" app:tint="?android:attr/textColorPrimary" tools:ignore="contentDescription" /> @@ -44,7 +44,7 @@ android:layout_height="wrap_content" android:layout_marginTop="46dp" android:gravity="center" - android:text="@string/exams_no_entries" + android:text="@string/exam_no_items" android:textSize="20sp" /> diff --git a/app/src/main/res/layout/fragment_grades.xml b/app/src/main/res/layout/fragment_grade.xml similarity index 99% rename from app/src/main/res/layout/fragment_grades.xml rename to app/src/main/res/layout/fragment_grade.xml index 604588644..bcead8e33 100644 --- a/app/src/main/res/layout/fragment_grades.xml +++ b/app/src/main/res/layout/fragment_grade.xml @@ -156,7 +156,7 @@ android:layout_marginTop="40dp" android:minHeight="100dp" android:minWidth="100dp" - app:srcCompat="@drawable/ic_menu_grade_26dp" + app:srcCompat="@drawable/ic_menu_main_grade_26dp" app:tint="?android:attr/textColorPrimary" tools:ignore="contentDescription" /> diff --git a/app/src/main/res/layout/fragment_login_form.xml b/app/src/main/res/layout/fragment_login_form.xml index 6e82b5280..e64384d32 100644 --- a/app/src/main/res/layout/fragment_login_form.xml +++ b/app/src/main/res/layout/fragment_login_form.xml @@ -29,7 +29,7 @@ android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginBottom="15dp" - android:text="@string/step_login" /> + android:text="@string/login_progress" /> + android:hint="@string/login_email_hint"> + android:hint="@string/login_password_hint"> @@ -120,7 +120,7 @@ android:layout_height="wrap_content" android:layout_marginBottom="30dp" android:layout_marginTop="20dp" - android:text="@string/action_sign_in" + android:text="@string/login_sign_in" android:textColor="@android:color/white" android:textStyle="bold" app:backgroundTint="@color/colorPrimary" /> diff --git a/app/src/main/res/layout/fragment_login_options.xml b/app/src/main/res/layout/fragment_login_options.xml index 9c9cbb964..be09acd17 100644 --- a/app/src/main/res/layout/fragment_login_options.xml +++ b/app/src/main/res/layout/fragment_login_options.xml @@ -27,11 +27,11 @@ android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginBottom="15dp" - android:text="@string/step_synchronization" /> + android:text="@string/login_sync" /> - \ No newline at end of file + android:layout_height="match_parent" /> + diff --git a/app/src/main/res/layout/fragment_timetable_tab.xml b/app/src/main/res/layout/fragment_timetable_tab.xml index 612b5df81..d4f0a55e1 100644 --- a/app/src/main/res/layout/fragment_timetable_tab.xml +++ b/app/src/main/res/layout/fragment_timetable_tab.xml @@ -34,7 +34,7 @@ android:layout_marginTop="40dp" android:minHeight="100dp" android:minWidth="100dp" - app:srcCompat="@drawable/ic_menu_timetable_24dp" + app:srcCompat="@drawable/ic_menu_main_timetable_24dp" app:tint="?android:attr/textColorPrimary" tools:ignore="contentDescription" /> @@ -44,7 +44,7 @@ android:layout_height="wrap_content" android:layout_marginTop="46dp" android:gravity="center" - android:text="@string/info_free_week" + android:text="@string/timetable_no_items" android:textSize="20sp" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/attendance_header.xml b/app/src/main/res/layout/header_attendance.xml similarity index 95% rename from app/src/main/res/layout/attendance_header.xml rename to app/src/main/res/layout/header_attendance.xml index 350b24522..7299eb6bf 100644 --- a/app/src/main/res/layout/attendance_header.xml +++ b/app/src/main/res/layout/header_attendance.xml @@ -1,7 +1,7 @@ @@ -79,7 +79,7 @@ android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_marginTop="10dp" - app:srcCompat="@drawable/ic_exclamation_24dp" + app:srcCompat="@drawable/ic_all_note_24dp" tools:ignore="contentDescription" /> diff --git a/app/src/main/res/layout/exams_header.xml b/app/src/main/res/layout/header_exam.xml similarity index 100% rename from app/src/main/res/layout/exams_header.xml rename to app/src/main/res/layout/header_exam.xml diff --git a/app/src/main/res/layout/grades_header.xml b/app/src/main/res/layout/header_grade.xml similarity index 94% rename from app/src/main/res/layout/grades_header.xml rename to app/src/main/res/layout/header_grade.xml index b819dd54c..79bfefd8b 100644 --- a/app/src/main/res/layout/grades_header.xml +++ b/app/src/main/res/layout/header_grade.xml @@ -4,7 +4,7 @@ android:id="@+id/grade_header_container" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@drawable/ic_border" + android:background="@drawable/ic_all_divider" android:foreground="?attr/selectableItemBackgroundBorderless" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" @@ -54,7 +54,7 @@ android:layout_marginEnd="10dp" android:layout_marginRight="10dp" android:layout_marginTop="5dp" - android:text="@string/info_grades_predicted_rating" + android:text="@string/grade_predicted" android:textColor="?android:attr/android:textColorSecondary" android:textSize="12sp" /> @@ -66,7 +66,7 @@ android:layout_marginTop="5dp" android:layout_toEndOf="@+id/grade_header_predicted_rating_text" android:layout_toRightOf="@+id/grade_header_predicted_rating_text" - android:text="@string/info_grades_final_rating" + android:text="@string/grade_final" android:textColor="?android:attr/android:textColorSecondary" android:textSize="12sp" /> @@ -77,6 +77,6 @@ android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_marginTop="10dp" - app:srcCompat="@drawable/ic_alert_24dp" + app:srcCompat="@drawable/ic_all_round_note_24dp" tool:ignore="contentDescription" /> diff --git a/app/src/main/res/layout/grades_summary_header.xml b/app/src/main/res/layout/header_grade_summary.xml similarity index 98% rename from app/src/main/res/layout/grades_summary_header.xml rename to app/src/main/res/layout/header_grade_summary.xml index 06954bd62..b291c9b20 100644 --- a/app/src/main/res/layout/grades_summary_header.xml +++ b/app/src/main/res/layout/header_grade_summary.xml @@ -31,4 +31,4 @@ android:text="@string/app_name" android:textSize="12sp" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/timetable_header.xml b/app/src/main/res/layout/header_timetable.xml similarity index 96% rename from app/src/main/res/layout/timetable_header.xml rename to app/src/main/res/layout/header_timetable.xml index 53ea8ce45..a029619e8 100644 --- a/app/src/main/res/layout/timetable_header.xml +++ b/app/src/main/res/layout/header_timetable.xml @@ -1,7 +1,7 @@ diff --git a/app/src/main/res/layout/attendance_subitem.xml b/app/src/main/res/layout/item_attendance.xml similarity index 93% rename from app/src/main/res/layout/attendance_subitem.xml rename to app/src/main/res/layout/item_attendance.xml index e16fc9fe8..a46451345 100644 --- a/app/src/main/res/layout/attendance_subitem.xml +++ b/app/src/main/res/layout/item_attendance.xml @@ -32,7 +32,7 @@ android:maxLength="2" android:text="0" android:textSize="32sp" - tool:ignore="all"/> + tool:ignore="all" /> + tool:ignore="all" /> @@ -70,8 +70,8 @@ android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_marginTop="10dp" - app:srcCompat="@drawable/ic_exclamation_24dp" - tool:ignore="contentDescription"/> + app:srcCompat="@drawable/ic_all_note_24dp" + tool:ignore="contentDescription" /> diff --git a/app/src/main/res/layout/exams_subitem.xml b/app/src/main/res/layout/item_exam.xml similarity index 97% rename from app/src/main/res/layout/exams_subitem.xml rename to app/src/main/res/layout/item_exam.xml index 3f50f07c4..736c528bc 100644 --- a/app/src/main/res/layout/exams_subitem.xml +++ b/app/src/main/res/layout/item_exam.xml @@ -9,7 +9,7 @@ @@ -59,7 +59,7 @@ android:layout_alignBottom="@+id/grade_subitem_value" android:layout_alignLeft="@+id/grade_subitem_description" android:layout_alignStart="@+id/grade_subitem_description" - android:text="@string/dialog_date_text" + android:text="@string/all_date" android:textSize="12sp" /> diff --git a/app/src/main/res/layout/grades_summary_subitem.xml b/app/src/main/res/layout/item_grade_summary.xml similarity index 92% rename from app/src/main/res/layout/grades_summary_subitem.xml rename to app/src/main/res/layout/item_grade_summary.xml index c7715092c..e42bc9ec0 100644 --- a/app/src/main/res/layout/grades_summary_subitem.xml +++ b/app/src/main/res/layout/item_grade_summary.xml @@ -6,7 +6,7 @@ android:id="@+id/grades_summary_subitem_predicted_container" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@drawable/ic_border" + android:background="@drawable/ic_all_divider" android:minHeight="35dp"> + android:paddingTop="5dp"> @@ -34,7 +34,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" - android:layout_marginBottom="10dp" + android:layout_marginBottom="5dp" android:text="@string/app_name" android:textSize="20sp" /> @@ -43,8 +43,9 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/loginItemName" + android:maxLines="2" android:text="@string/app_name" - android:textSize="17sp" /> + android:textSize="13sp" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/timetable_subitem.xml b/app/src/main/res/layout/item_timetable.xml similarity index 96% rename from app/src/main/res/layout/timetable_subitem.xml rename to app/src/main/res/layout/item_timetable.xml index 3c3cdc42a..5d30a2798 100644 --- a/app/src/main/res/layout/timetable_subitem.xml +++ b/app/src/main/res/layout/item_timetable.xml @@ -59,7 +59,7 @@ android:layout_alignLeft="@id/timetable_subItem_lesson" android:layout_alignStart="@id/timetable_subItem_lesson" android:maxLines="1" - android:text="@string/grades_text" + android:text="@string/app_name" android:textColor="?android:attr/android:textColorSecondary" android:textSize="12sp" /> @@ -75,7 +75,7 @@ android:layout_toEndOf="@+id/timetable_subItem_time" android:layout_toRightOf="@+id/timetable_subItem_time" android:maxLines="1" - android:text="@string/grades_text" + android:text="@string/app_name" android:textColor="?android:attr/android:textColorSecondary" android:textSize="12sp" tool:ignore="all"/> @@ -87,7 +87,7 @@ android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:layout_marginTop="10dp" - app:srcCompat="@drawable/ic_swap_30dp" + app:srcCompat="@drawable/ic_timetable_swap_30dp" tool:ignore="contentDescription"/> diff --git a/app/src/main/res/layout/timetable_widget_item.xml b/app/src/main/res/layout/item_widget_timetable.xml similarity index 99% rename from app/src/main/res/layout/timetable_widget_item.xml rename to app/src/main/res/layout/item_widget_timetable.xml index d97be4af0..6b0e73ee4 100644 --- a/app/src/main/res/layout/timetable_widget_item.xml +++ b/app/src/main/res/layout/item_widget_timetable.xml @@ -64,4 +64,4 @@ android:textSize="12sp" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/timetable_widget.xml b/app/src/main/res/layout/widget_timetable.xml similarity index 96% rename from app/src/main/res/layout/timetable_widget.xml rename to app/src/main/res/layout/widget_timetable.xml index acf8d238c..9a2a79f54 100644 --- a/app/src/main/res/layout/timetable_widget.xml +++ b/app/src/main/res/layout/widget_timetable.xml @@ -53,7 +53,7 @@ android:ellipsize="end" android:gravity="center_vertical" android:maxLines="1" - android:text="@string/timetable_text" + android:text="@string/timetable_title" android:textColor="@android:color/white" android:textSize="20sp" /> @@ -69,7 +69,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:text="@string/widget_timetable_no_lesson" + android:text="@string/widget_timetable_no_items" android:textColor="@android:color/black" android:textSize="20sp" /> diff --git a/app/src/main/res/menu/grades_action_menu.xml b/app/src/main/res/menu/action_menu_grade.xml similarity index 69% rename from app/src/main/res/menu/grades_action_menu.xml rename to app/src/main/res/menu/action_menu_grade.xml index 0533ae39e..3f0ff786b 100644 --- a/app/src/main/res/menu/grades_action_menu.xml +++ b/app/src/main/res/menu/action_menu_grade.xml @@ -5,16 +5,15 @@ - diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 7dc7ba953..e7505a895 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -1,173 +1,166 @@ Wulkanowy - - Zaloguj się - Zaloguj się za pomocą konta ucznia lub rodzica - Podaj symbol dziennika VULCAN - Email - Hasło - Symbol - Zaloguj - Łączenie z dziennikiem - Logowanie - Synchronizacja - Ten adres email nie jest poprawny - To hasło jest za krótkie - To hasło jest niepoprawne - Nie znaleziono ucznia. Sprwadź symbol - To pole jest wymagane - Brak dostępu do dziennika. Sprawdź inny symbol - Pomyślnie zalogowano - Niepoprawny e-mail lub hasło - Brak uprawnień do otwarcia dziennika. Sprawdź wprowadzoną nazwę powiatu - Logowanie nie powiodło się. Spróbuj ponownie lub zrestartuj aplikację - Nie masz jeszcze konta? Załóż je - Zapomniałeś hasła? - Wybierz ucznia + + Wybierz ucznia + Wulkanowy + Oceny + Frekwencja + Sprawdziany + Plan lekcji + Ustawienia + Więcej - Czarny - Czerwony - Niebieski - Zielony - Brak koloru - Główna aktywność - Sprawdziany - Oceny - Frekwencja - Plan lekcji - Ustawienia - Więcej - Ta część aplikacji jest w budowie - Brak ocen + + Zaloguj się za pomocą konta ucznia lub rodzica + Podaj symbol dziennika VULCAN + Email + Hasło + Symbol + Zaloguj + Logowanie… + Synchronizacja + Ten adres email nie jest poprawny + To hasło jest za krótkie + To hasło jest niepoprawne + Nie znaleziono ucznia. Sprwadź symbol + To pole jest wymagane - Brak połączenia z internetem - Szyfrowanie nie powiodło się. Automatyczne logowanie zostało wyłączone - Wersja %1$s - "Podczas odświeżania zawartości wystąpił błąd. " - Blokada aplikacji - W obawie o bezpieczeństwo przechowywanych danych osobistych na urządzeniu z podwyższonymi uprawnieniami (root), aplikacja Wulkanowy została zablokowana - Opis - Waga - Brak opisu - Nauczyciel - Data - Kolor - - Zmień semestr - Semestr %d - Anuluj - - Lekcja - Sala - Grupa - Godziny - Zmiany - - Synchronizacja zakończona - - Szczegóły - Zamknij - Nauczyciel - - Brak danych - Zbyt długie oczekiwanie na połączenie - - Brak nowych ocen - Ilość nowych ocen: %1$d - - Średnia: %1$.2f - Brak średniej - Przewidywana: %1$s - Końcowa: %1$s - Brak lekcji w tym tygodniu - Sala %s - - Przewidywana - Końcowa - - + + Ocena + Semestr %d + Zmień semestr + Brak ocen + Waga + Brak nowych ocen + Ilość nowych ocen: %1$d + Średnia: %1$.2f + Brak średniej + Przewidywana: %1$s + Końcowa: %1$s + Obliczona średnia + Szacowana średnia + Końcowa średnia + Podsumowanie + %d ocena %d oceny %d ocen %d ocen - + Nowa ocena Nowe oceny Nowych ocen Nowych ocen - - Dostałeś %1$d ocenę - "Dostałeś %1$d oceny - Dostałeś %1$d ocen - Dostałeś %1$d ocen - - Nieobecny z przyczyn szkolnych + + Lekcja + Sala %s + Grupa + Godziny + Zmiany + Brak lekcji w tym tygodniu + + + + Nieobecny z przyczyn szkolnych Nieobecność usprawiedliwiona Nieobecność nieusprawiedliwiona Zwolniony Spóźnienie usprawiedliowione Spóźnienie nieusprawiedliwione Obecny - Opis - Data - Przedmiot - Numer lekcji - Brak wpisów - + Numer lekcji + Brak wpisów + %1$d nieobecność %1$d nieobecności %1$d nieobecności + + Brak sprawdzianów w tym tygodniu + Typ + Data wpisu + + + + Opis + Brak opisu + Nauczyciel + Data + Kolor + Szczegóły + Zamknij + Brak danych + Przedmiot + + + + Brak lekcji + Dziś + Jutro + + + Widok - Domyślny widok - Pokazuj podsumowanie w ocenach - Pokazuj obecność we frekwencji - Wymagany restart + Domyślny widok + Pokazuj podsumowanie w ocenach + Pokazuj obecność we frekwencji Ciemny motyw (Beta) Powiadomienia Pokazuj powiadomienia Usługi - Włącz odświeżanie danych w tle - Zawieszone na wakacjach - Interwał między odświeżaniem danych - Synchronizacja tylko przez WiFi + Automatyczna aktualizacja + Zawieszone na wakacjach + Interwał aktualizacji + Tylko WiFi - O aplikacji - Informacje o Wulkanowym - Wulkanowy to nieoficjalny klient dziennika VULCAN UONET+ + Informacje o Wulkanowym Wersja Licencje open source Szczegóły licencji na oprogramowanie open source Kod źródłowy i feedback + Nie, nie zostaniesz programistą! Musisz bardziej się postarać! Kliknij jeszcze parę razy - Odwiedź zakładkę Kod źródłowy i pokaż jaki z ciebie programista! + Odwiedź zakładkę Kod źródłowy i pokaż jaki z ciebie programista! - Nowe oceny - Brak lekcji - Dziś - Jutro - Brak sprawdzianów w tym tygodniu - Typ - Data wpisu + Wymagany restart - Obliczona średnia - Szacowana średnia - Końcowa średnia - Podsumowanie - Szczegóły - Podczas synchronizacji wystąpił błąd + + + Nowe oceny + + Dostałeś %1$d ocenę + "Dostałeś %1$d oceny + Dostałeś %1$d ocen + Dostałeś %1$d ocen + + + + + Czarny + Czerwony + Niebieski + Zielony + Brak koloru + + + + Brak połączenia z internetem + Synchronizacja zakończona + Podczas synchronizacji wystąpił błąd + Zbyt długie oczekiwanie na połączenie + Logowanie nie powiodło się. Spróbuj ponownie lub zrestartuj aplikację diff --git a/app/src/main/res/values-pl/prefernces_array.xml b/app/src/main/res/values-pl/value_prefernces.xml similarity index 100% rename from app/src/main/res/values-pl/prefernces_array.xml rename to app/src/main/res/values-pl/value_prefernces.xml diff --git a/app/src/main/res/values/symbols.xml b/app/src/main/res/values/api_symbols.xml similarity index 100% rename from app/src/main/res/values/symbols.xml rename to app/src/main/res/values/api_symbols.xml diff --git a/app/src/main/res/values/identificators.xml b/app/src/main/res/values/identificators.xml deleted file mode 100644 index fa7b1f199..000000000 --- a/app/src/main/res/values/identificators.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 53e317ec2..de18d8a3f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,169 +1,159 @@ Wulkanowy - - Sign in - Sign in with student or parent account - Enter the VULCAN diary symbol - Email - Password - Symbol - Sign in - Connecting with log - Login… - Synchronization… - This email address is invalid - This password is too short - This password is incorrect - No student found. Check the symbol - This field is required - No permission to open log. Check another symbol - Login is successful - Bad e-mail or password - No permission to open log. Check entered symbol - Login is failed. Try again or restart the app - No account yet? Create one - Forgot password? - Select student + + Select student + Wulkanowy + Grades + Attendance + Exams + Timetable + Settings + More - Black - Red - Blue - Green - No color - Main Activity - Exams - Grades - Attendance - Timetable - Settings - More - This section of app is under construction. - No grades + + Sign in with the student or parent account + Enter the VULCAN diary symbol + Email + Password + Symbol + Sign in + Logging in… + Synchronization… + This email address is invalid + This password is too short + This password is incorrect + Student not found. Check the symbol + This field is required - No internet connection - Encryption failed. Automatic login has been disabled - Version %1$s - An error occurred while refreshing the content. - Application lock - For the sake of safety of personal data stored on a device with increased authorization (root), the Wulkanowy application has been blocked. - Description - Weight - No description - Teacher - Date - Color - - Switch semester - Semester %d - Cancel - - Lesson - Room - Group - Times - Changes - - Synchronization completed - - Details - Close - Teacher - - No data - Too long wait for connection - - No new grades - Number of new grades: %1$d - - Average: %1$.2f - No average - Predicted: %1$s - Final: %1$s - No lesson in this week - - Predicted - Final - - Room %s - - + + Grade + Semester %d + Change semester + No grades + Weight + No new grades + Number of new ratings: %1$d + Average: %1$.2f + No average + Predicted: %1$s + Final: %1$s + Calculated average + Predicted average + Final average + Summary + %d grade %d grades - + New grade New grades - - You received %1$d grade - You received %1$d grades - - Absence for school reasons - Absence excused + + Lesson + Room %s + Group + Hours + Changes + No lesson in this week + + + + Absent for school reasons + Excused absence Unexcused absence Exemption Excused lateness Unexcused lateness Present - Description - Date - Subject - Lesson number - No entries - + Number of lesson + No entries + %1$d absence - %1$d absences - %1$d absences %1$d absences - View - Default view after startup - Show summary in grades - Show present in attendance - Required restart + + No exams in this week + Type + Entry date + + + + Description + No description + Teacher + Date + Color + Details + Close + No data + Subject + + + + No lesson + Today + Tomorrow + + + + View + Default view + Show the summary in the grades + Show presence in attendance Dark theme (Beta) Notifications - Show the notifications + Show notifications Services - Enable background data refreshing - Suspended on holidays - Interval between data refreshing - Synchronization via WiFi only + Automatic update + Suspended on holiday + Updates interval + Only WiFi - About - About Wulkanowy - Wulkanowy is an unofficial VULCAN UONET+ log client + About Wulkanowy Version - Open source licenses + Open source licences License details for open source software Source code & feedback + No, you will not become a programmer! You must try harder! Click a few more times - Visit the Source code tab and show how good a programmer you are! + Visit the Source code tab and show how good a programmer you are! - New grades - No lessons - Today - Tomorrow - No exams in this week - Type - Date of entry + Restart required - Calculated average - Predicted average - Final average - Summary - Details - An error has occurred during synchronization + + + New grades + + You received %1$d grade + You received %1$d grades + + + + + Black + Red + Blue + Green + No color + + + + No internet connection + Synchronization complete + There was an error during synchronization + Too long wait for connection + Login is failed. Try again or restart the app diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index c7506e2d4..94f9ecb93 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -33,7 +33,7 @@
diff --git a/app/src/main/res/values/prefernces_array.xml b/app/src/main/res/values/value_prefernces.xml similarity index 87% rename from app/src/main/res/values/prefernces_array.xml rename to app/src/main/res/values/value_prefernces.xml index 59f4fffed..b855e24c5 100644 --- a/app/src/main/res/values/prefernces_array.xml +++ b/app/src/main/res/values/value_prefernces.xml @@ -1,10 +1,10 @@ - @string/grades_text - @string/attendance_text - @string/exams_text - @string/timetable_text + @string/grade_title + @string/attendance_title + @string/exam_title + @string/timetable_title 0 diff --git a/app/src/main/res/xml/identificators.xml b/app/src/main/res/xml/identificators.xml new file mode 100644 index 000000000..2d1873f48 --- /dev/null +++ b/app/src/main/res/xml/identificators.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/app/src/main/res/xml/widget_provider.xml b/app/src/main/res/xml/provider_widget_timetable.xml similarity index 61% rename from app/src/main/res/xml/widget_provider.xml rename to app/src/main/res/xml/provider_widget_timetable.xml index a140a6c16..cffa24ff4 100644 --- a/app/src/main/res/xml/widget_provider.xml +++ b/app/src/main/res/xml/provider_widget_timetable.xml @@ -1,9 +1,9 @@ \ No newline at end of file + android:widgetCategory="home_screen" /> diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/scheme_preferences.xml similarity index 85% rename from app/src/main/res/xml/preferences.xml rename to app/src/main/res/xml/scheme_preferences.xml index 9944cba68..ae687aa81 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/scheme_preferences.xml @@ -7,17 +7,17 @@ android:entryValues="@array/startup_tab_value" android:key="startup_tab" android:summary="%s" - android:title="@string/pref_tab_list" /> + android:title="@string/pref_view_list" /> + android:summary="@string/pref_restart" + android:title="@string/pref_view_summary" /> + android:summary="@string/pref_restart" + android:title="@string/pref_view_present" /> + android:title="@string/pref_services_wifi" />
- + diff --git a/app/src/test/java/io/github/wulkanowy/data/repositories/remote/StudentRemoteTest.kt b/app/src/test/java/io/github/wulkanowy/data/repositories/remote/StudentRemoteTest.kt index b06113ab0..ed2a06fad 100644 --- a/app/src/test/java/io/github/wulkanowy/data/repositories/remote/StudentRemoteTest.kt +++ b/app/src/test/java/io/github/wulkanowy/data/repositories/remote/StudentRemoteTest.kt @@ -1,64 +1,32 @@ package io.github.wulkanowy.data.repositories.remote -import io.github.wulkanowy.api.StudentAndParent -import io.github.wulkanowy.api.Vulcan -import io.github.wulkanowy.api.generic.School -import io.github.wulkanowy.api.login.AccountPermissionException +import io.github.wulkanowy.api.Api +import io.github.wulkanowy.api.register.Pupil +import io.reactivex.Single +import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test -import org.mockito.ArgumentMatchers.any import org.mockito.Mock -import org.mockito.Mockito.* +import org.mockito.Mockito.doReturn import org.mockito.MockitoAnnotations -import io.github.wulkanowy.api.generic.Student as StudentApi class StudentRemoteTest { @Mock - private lateinit var mockApi: Vulcan + private lateinit var mockApi: Api @Before fun initApi() { MockitoAnnotations.initMocks(this) - doNothing().`when`(mockApi).setCredentials(any(), any(), any(), any(), any(), any()) } @Test fun testRemoteAll() { - `when`(mockApi.symbols).thenReturn(mutableListOf("przeworsk", "jaroslaw", "zarzecze")) - `when`(mockApi.schools).thenReturn(mutableListOf( - School("ZSTIO", "123", false), - School("ZSZ", "998", true))) - - val mockSnP = mock(StudentAndParent::class.java) - `when`(mockSnP.students).thenReturn(mutableListOf( - StudentApi().apply { - id = "20" - name = "Włodzimierz" - isCurrent = false - })) - `when`(mockApi.studentAndParent).thenReturn(mockSnP) + doReturn(Single.just(listOf(Pupil("", "", "", "test", "", "")))) + .`when`(mockApi).getPupils() val students = StudentRemote(mockApi).getConnectedStudents("", "", "").blockingGet() - assert(students.size == 6) - assert(students[3].studentName == "Włodzimierz") - - } - - @Test - fun testOneEmptySymbol() { - doReturn(mutableListOf("przeworsk")).`when`(mockApi).symbols - doThrow(AccountPermissionException::class.java).`when`(mockApi).schools - - val students = StudentRemote(mockApi).getConnectedStudents("", "", "").blockingGet() - assert(students.isEmpty()) - } - - @Test - fun testDefaultSymbol() { - doReturn(listOf("Default")).`when`(mockApi).symbols - - val students = StudentRemote(mockApi).getConnectedStudents("", "", "").blockingGet() - assert(students.isEmpty()) + assertEquals(1, students.size) + assertEquals("test", students.first().studentName) } } diff --git a/app/src/test/java/io/github/wulkanowy/ui/login/options/LoginOptionsPresenterTest.kt b/app/src/test/java/io/github/wulkanowy/ui/login/options/LoginOptionsPresenterTest.kt index 640457f8c..1b4696f79 100644 --- a/app/src/test/java/io/github/wulkanowy/ui/login/options/LoginOptionsPresenterTest.kt +++ b/app/src/test/java/io/github/wulkanowy/ui/login/options/LoginOptionsPresenterTest.kt @@ -4,6 +4,7 @@ import io.github.wulkanowy.TestSchedulers import io.github.wulkanowy.data.ErrorHandler import io.github.wulkanowy.data.db.entities.Student import io.github.wulkanowy.data.repositories.StudentRepository +import io.reactivex.Completable import io.reactivex.Single import org.junit.Before import org.junit.Test @@ -61,8 +62,8 @@ class LoginOptionsPresenterTest { @Test fun onSelectedStudentTest() { + doReturn(Completable.complete()).`when`(repository).save(testStudent) presenter.onSelectStudent(testStudent) - verify(repository).save(testStudent) verify(loginOptionsView).showLoginProgress(true) verify(loginOptionsView).openMainView() @@ -70,7 +71,7 @@ class LoginOptionsPresenterTest { @Test fun onSelectedStudentErrorTest() { - doThrow(testException).`when`(repository).save(testStudent) + doReturn(Completable.error(testException)).`when`(repository).save(testStudent) presenter.onSelectStudent(testStudent) verify(loginOptionsView).showLoginProgress(true) verify(errorHandler).proceed(testException) diff --git a/build.gradle b/build.gradle index 4df2c909a..c8ce30150 100644 --- a/build.gradle +++ b/build.gradle @@ -5,25 +5,20 @@ buildscript { google() jcenter() maven { url "https://plugins.gradle.org/m2/" } + maven { url 'https://maven.fabric.io/public' } } dependencies { - classpath 'com.android.tools.build:gradle:3.1.4' - classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.2" - classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4' - classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath 'com.android.tools.build:gradle:3.1.4' + classpath "io.fabric.tools:gradle:1.25.4" + classpath "com.google.gms:oss-licenses:0.9.2" + classpath "com.github.triplet.gradle:play-publisher:1.2.2" + classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6.2" } } -plugins { - // gradle dependencyUpdates -Drevision=release - id "com.github.ben-manes.versions" version "0.20.0" -} - project.ext.preDexLibs = !project.hasProperty("disablePreDex") subprojects { - apply plugin: 'build-dashboard' // build/reports/buildDashboard/index.html - project.plugins.whenPluginAdded { plugin -> if ("com.android.build.gradle.AppPlugin" == plugin.class.name) { project.android.dexOptions.preDexLibraries = rootProject.ext.preDexLibs @@ -33,60 +28,16 @@ subprojects { } } -ext { - GROUP_ID = "io.github.wulkanowy" - - supportVersion = "27.1.1" - flexibleAdapter = "5.0.5" - flexibleUi = "1.0.0-b5" - firebaseJob = "0.8.5" - apacheLang = "3.7" - apacheCollections = "4.2" - butterknife = "8.8.1" - threeTenABP = "1.1.0" - dagger2 = "2.17" - ahbottom = "2.2.0" - jsoup = "1.11.3" - gson = "2.8.5" - ossLicenses = "16.0.0" - slf4jApi = "1.7.25" - slf4jTimber = "1.0.1" - timber = "4.7.1" - - debugDb = "1.0.4" - - junit = "4.12" - mockito = "2.19.1" - testRunner = "1.0.2" - - fabricGradle = "1.25.4" - crashlyticsSdk = "2.9.4" - crashlyticsAnswers = "1.4.2" - - playPublisher = "1.2.2" -} - allprojects { repositories { mavenCentral() google() jcenter() + maven { url 'https://maven.fabric.io/public'} + maven { url 'https://jitpack.io' } } } task clean(type: Delete) { delete rootProject.buildDir } - -dependencyUpdates.resolutionStrategy { - componentSelection { rules -> - rules.all { ComponentSelection selection -> - boolean rejected = ['alpha', 'beta', 'rc', 'cr', 'm'].any { qualifier -> - selection.candidate.version ==~ /(?i).*[.-]${qualifier}[.\d-]*/ - } - if (rejected) { - selection.reject('Release candidate') - } - } - } -} diff --git a/settings.gradle b/settings.gradle index d55cd7786..e7b4def49 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':app', ':api' +include ':app' From 6b07a56a1b5aefe53496a2741e20b4241c13ee8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj?= Date: Sat, 22 Sep 2018 23:01:19 +0200 Subject: [PATCH 033/263] Created issue template (#159) --- .github/ISSUE_TEMPLATE.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..27d57f599 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,17 @@ +## Co powinno się dziać + + +## Co się dzieje + + +## Jak to zrobić kolejny raz: + + 1. + 2. + 3. + +## Informacje o urządzeniu i dzienniku + + - Wersja aplikacji: + - Wersja Androida: + - Adres URL dziennika: From a1f64baca4ce0a671b0f5833d42d1e13d1d96049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Mon, 24 Sep 2018 15:21:47 +0200 Subject: [PATCH 034/263] Refactor exam module (#157) --- app/build.gradle | 12 +- .../data/repositories/local/ExamLocalTest.kt | 50 ++++ ...tudentLocalTest.kt => SessionLocalTest.kt} | 14 +- app/src/main/AndroidManifest.xml | 5 +- .../github/wulkanowy/data/RepositoryModule.kt | 11 + .../github/wulkanowy/data/db/AppDatabase.kt | 12 +- .../io/github/wulkanowy/data/db/Converters.kt | 14 + .../github/wulkanowy/data/db/dao/ExamDao.kt | 22 ++ .../wulkanowy/data/db/dao/SemesterDao.kt | 7 +- .../wulkanowy/data/db/dao/StudentDao.kt | 4 +- .../github/wulkanowy/data/db/entities/Exam.kt | 38 +++ .../wulkanowy/data/db/entities/Semester.kt | 12 +- .../data/repositories/ExamRepository.kt | 39 +++ ...dentRepository.kt => SessionRepository.kt} | 31 ++- .../data/repositories/local/ExamLocal.kt | 28 ++ .../data/repositories/local/SessionLocal.kt | 49 ++++ .../data/repositories/local/StudentLocal.kt | 37 --- .../data/repositories/remote/ExamRemote.kt | 37 +++ .../data/repositories/remote/SessionRemote.kt | 59 +++++ .../data/repositories/remote/StudentRemote.kt | 32 --- .../java/io/github/wulkanowy/di/AppModule.kt | 5 +- .../ui/login/form/LoginFormPresenter.kt | 8 +- .../ui/login/options/LoginOptionsFragment.kt | 22 +- .../ui/login/options/LoginOptionsPresenter.kt | 6 +- .../wulkanowy/ui/main/exam/ExamDialog.kt | 51 ++++ .../wulkanowy/ui/main/exam/ExamFragment.kt | 89 ++++++- .../wulkanowy/ui/main/exam/ExamHeader.kt | 59 +++++ .../github/wulkanowy/ui/main/exam/ExamItem.kt | 52 ++++ .../wulkanowy/ui/main/exam/ExamPresenter.kt | 98 +++++++ .../github/wulkanowy/ui/main/exam/ExamView.kt | 28 ++ .../wulkanowy/ui/splash/SplashActivity.kt | 4 +- .../wulkanowy/ui/splash/SplashPresenter.kt | 6 +- .../github/wulkanowy/ui/splash/SplashView.kt | 4 +- .../io/github/wulkanowy/utils/TimeUtils.kt | 23 +- .../utils/extension/DateExtension.kt | 25 ++ .../extension/FlexibleAdapterExtension.kt | 8 +- app/src/main/res/layout/dialog_exam.xml | 242 +++++++----------- app/src/main/res/layout/fragment_exam.xml | 111 ++++++-- app/src/main/res/layout/fragment_exam_tab.xml | 64 ----- app/src/main/res/layout/header_exam.xml | 8 +- app/src/main/res/layout/item_exam.xml | 91 +++---- app/src/main/res/values-pl/strings.xml | 3 + app/src/main/res/values/strings.xml | 2 + app/src/main/res/values/styles.xml | 8 + .../repositories/remote/ExamRemoteTest.kt | 56 ++++ .../repositories/remote/StudentRemoteTest.kt | 2 +- .../ui/login/form/LoginFormPresenterTest.kt | 4 +- .../options/LoginOptionsPresenterTest.kt | 10 +- .../ui/splash/SplashPresenterTest.kt | 14 +- .../github/wulkanowy/utils/TimeUtilsTest.kt | 82 +++--- build.gradle | 2 +- 51 files changed, 1220 insertions(+), 480 deletions(-) create mode 100644 app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/ExamLocalTest.kt rename app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/{StudentLocalTest.kt => SessionLocalTest.kt} (69%) create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/Converters.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/dao/ExamDao.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/db/entities/Exam.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/repositories/ExamRepository.kt rename app/src/main/java/io/github/wulkanowy/data/repositories/{StudentRepository.kt => SessionRepository.kt} (59%) create mode 100644 app/src/main/java/io/github/wulkanowy/data/repositories/local/ExamLocal.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/repositories/local/SessionLocal.kt delete mode 100644 app/src/main/java/io/github/wulkanowy/data/repositories/local/StudentLocal.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/repositories/remote/ExamRemote.kt create mode 100644 app/src/main/java/io/github/wulkanowy/data/repositories/remote/SessionRemote.kt delete mode 100644 app/src/main/java/io/github/wulkanowy/data/repositories/remote/StudentRemote.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamDialog.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamHeader.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamItem.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamPresenter.kt create mode 100644 app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamView.kt create mode 100644 app/src/main/java/io/github/wulkanowy/utils/extension/DateExtension.kt delete mode 100644 app/src/main/res/layout/fragment_exam_tab.xml create mode 100644 app/src/test/java/io/github/wulkanowy/data/repositories/remote/ExamRemoteTest.kt diff --git a/app/build.gradle b/app/build.gradle index 9a870db5b..5acb3931e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,8 +8,8 @@ apply from: 'sonarqube.gradle' apply plugin: 'com.github.triplet.play' android { - compileSdkVersion 27 - buildToolsVersion '27.0.3' + compileSdkVersion 28 + buildToolsVersion '28.0.2' playAccountConfigs { defaultAccountConfig { @@ -22,7 +22,7 @@ android { applicationId "io.github.wulkanowy" testApplicationId "io.github.tests.wulkanowy" minSdkVersion 15 - targetSdkVersion 27 + targetSdkVersion 28 versionCode 16 versionName "0.5.2" multiDexEnabled true @@ -68,11 +68,11 @@ play { uploadImages = true } -ext.supportVersion = "27.1.1" +ext.supportVersion = "28.0.0-rc02" dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - implementation 'com.github.wulkanowy:api:88ede83149' + implementation 'com.github.wulkanowy:api:ad57669' implementation "com.android.support:support-v4:$supportVersion" implementation "com.android.support:design:$supportVersion" @@ -98,7 +98,7 @@ dependencies { implementation 'com.github.pwittchen:reactivenetwork-rx2:2.1.0' implementation 'io.reactivex.rxjava2:rxandroid:2.0.2' - implementation "io.reactivex.rxjava2:rxjava:2.2.0" + implementation "io.reactivex.rxjava2:rxjava:2.2.1" implementation "org.apache.commons:commons-lang3:3.8" implementation "org.apache.commons:commons-collections4:4.2" diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/ExamLocalTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/ExamLocalTest.kt new file mode 100644 index 000000000..011632735 --- /dev/null +++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/ExamLocalTest.kt @@ -0,0 +1,50 @@ +package io.github.wulkanowy.data.repositories.local + +import android.arch.persistence.room.Room +import android.support.test.InstrumentationRegistry +import android.support.test.runner.AndroidJUnit4 +import io.github.wulkanowy.data.db.AppDatabase +import io.github.wulkanowy.data.db.entities.Exam +import io.github.wulkanowy.data.db.entities.Semester +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.threeten.bp.LocalDate +import java.sql.Date +import kotlin.test.assertEquals + +@RunWith(AndroidJUnit4::class) +class ExamLocalTest { + + private lateinit var examLocal: ExamLocal + + private lateinit var testDb: AppDatabase + + @Before + fun createDb() { + testDb = Room.inMemoryDatabaseBuilder(InstrumentationRegistry.getContext(), AppDatabase::class.java).build() + examLocal = ExamLocal(testDb.examsDao()) + } + + @After + fun closeDb() { + testDb.close() + } + + @Test + fun saveAndReadTest() { + examLocal.saveExams(listOf( + Exam(studentId = "1", diaryId = "2", date = Date.valueOf("2018-09-10")), + Exam(studentId = "1", diaryId = "2", date = Date.valueOf("2018-09-14")), + Exam(studentId = "1", diaryId = "2", date = Date.valueOf("2018-09-17")) // in next week + )) + + val exams = examLocal + .getExams(Semester(studentId = "1", diaryId = "2", semesterId = "3"), LocalDate.of(2018, 9, 10)) + .blockingGet() + assertEquals(2, exams.size) + assertEquals(exams[0].date, Date.valueOf("2018-09-10")) + assertEquals(exams[1].date, Date.valueOf("2018-09-14")) + } +} diff --git a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/StudentLocalTest.kt b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/SessionLocalTest.kt similarity index 69% rename from app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/StudentLocalTest.kt rename to app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/SessionLocalTest.kt index 7103d478b..17264c956 100644 --- a/app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/StudentLocalTest.kt +++ b/app/src/androidTest/java/io/github/wulkanowy/data/repositories/local/SessionLocalTest.kt @@ -14,9 +14,9 @@ import org.junit.runner.RunWith import kotlin.test.assertEquals @RunWith(AndroidJUnit4::class) -class StudentLocalTest { +class SessionLocalTest { - private lateinit var studentLocal: StudentLocal + private lateinit var studentLocal: SessionLocal private lateinit var testDb: AppDatabase @@ -28,7 +28,7 @@ class StudentLocalTest { testDb = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java) .build() sharedHelper = SharedPrefHelper(context.getSharedPreferences("TEST", Context.MODE_PRIVATE)) - studentLocal = StudentLocal(testDb.studentDao(), sharedHelper, context) + studentLocal = SessionLocal(testDb.studentDao(), testDb.semesterDao(), sharedHelper, context) } @After @@ -38,12 +38,12 @@ class StudentLocalTest { @Test fun saveAndReadTest() { - studentLocal.save(Student(email = "test", password = "test123", schoolId = "23")).blockingAwait() - assert(sharedHelper.getLong(StudentLocal.CURRENT_USER_KEY, 0) == 1L) + studentLocal.saveStudent(Student(email = "test", password = "test123", schoolId = "23")).blockingAwait() + assert(sharedHelper.getLong(SessionLocal.LAST_USER_KEY, 0) == 1L) - assert(studentLocal.isStudentLoggedIn) + assert(studentLocal.isSessionSaved) - val student = studentLocal.getCurrentStudent().blockingGet() + val student = studentLocal.getLastStudent().blockingGet() assertEquals("23", student.schoolId) } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 47e6e013e..21c7bc994 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,5 +1,6 @@ @@ -13,7 +14,9 @@ android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" - android:theme="@style/WulkanowyTheme"> + android:theme="@style/WulkanowyTheme" + android:usesCleartextTraffic="true" + tools:targetApi="m"> ): List + + @Delete + fun deleteAll(exams: List) + + @Query("SELECT * FROM Exams WHERE diary_id = :diaryId AND student_id = :studentId AND date >= :from AND date <= :end") + fun getExams(diaryId: String, studentId: String, from: Date, end: Date): Maybe> +} diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/SemesterDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/SemesterDao.kt index a8ebb4788..363da09b4 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/SemesterDao.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/SemesterDao.kt @@ -3,11 +3,16 @@ package io.github.wulkanowy.data.db.dao import android.arch.persistence.room.Dao import android.arch.persistence.room.Insert import android.arch.persistence.room.OnConflictStrategy.REPLACE +import android.arch.persistence.room.Query import io.github.wulkanowy.data.db.entities.Semester +import io.reactivex.Single @Dao interface SemesterDao { @Insert(onConflict = REPLACE) - fun insert(semester: Semester): Long + fun insertAll(semester: List) + + @Query("SELECT * FROM Semesters WHERE student_id = :studentId") + fun getSemester(studentId: String): Single> } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt b/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt index fb3cb4e73..08ca48d23 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/StudentDao.kt @@ -5,7 +5,7 @@ import android.arch.persistence.room.Insert import android.arch.persistence.room.OnConflictStrategy.REPLACE import android.arch.persistence.room.Query import io.github.wulkanowy.data.db.entities.Student -import io.reactivex.Single +import io.reactivex.Maybe @Dao interface StudentDao { @@ -14,5 +14,5 @@ interface StudentDao { fun insert(student: Student): Long @Query("SELECT * FROM Students WHERE id = :id") - fun load(id: Long): Single + fun load(id: Long): Maybe } diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Exam.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Exam.kt new file mode 100644 index 000000000..64f9857df --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Exam.kt @@ -0,0 +1,38 @@ +package io.github.wulkanowy.data.db.entities + +import android.arch.persistence.room.ColumnInfo +import android.arch.persistence.room.Entity +import android.arch.persistence.room.PrimaryKey +import java.io.Serializable +import java.util.* + +@Entity(tableName = "Exams") +data class Exam( + + @PrimaryKey(autoGenerate = true) + var id: Long = 0, + + @ColumnInfo(name = "student_id") + var studentId: String = "", + + @ColumnInfo(name = "diary_id") + var diaryId: String = "", + + var date: Date, + + @ColumnInfo(name = "entry_date") + var entryDate: Date = Date(), + + var subject: String = "", + + var group: String = "", + + var type: String = "", + + var description: String = "", + + var teacher: String = "", + + @ColumnInfo(name = "teacher_symbol") + var teacherSymbol: String = "" +) : Serializable diff --git a/app/src/main/java/io/github/wulkanowy/data/db/entities/Semester.kt b/app/src/main/java/io/github/wulkanowy/data/db/entities/Semester.kt index dec731d7a..5ef1f359b 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/entities/Semester.kt +++ b/app/src/main/java/io/github/wulkanowy/data/db/entities/Semester.kt @@ -6,12 +6,15 @@ import android.arch.persistence.room.Index import android.arch.persistence.room.PrimaryKey @Entity(tableName = "Semesters", - indices = [Index(value = ["diary_id", "semester_id"], unique = true)]) + indices = [Index(value = ["semester_id", "diary_id", "student_id"], unique = true)]) data class Semester( - @PrimaryKey + @PrimaryKey(autoGenerate = true) var id: Long = 0, + @ColumnInfo(name = "student_id") + var studentId: String, + @ColumnInfo(name = "diary_id") var diaryId: String, @@ -22,5 +25,8 @@ data class Semester( var semesterId: String, @ColumnInfo(name = "semester_name") - var semesterName: String = "" + var semesterName: Int = 0, + + @ColumnInfo(name = "is_current") + var current: Boolean = false ) diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/ExamRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/ExamRepository.kt new file mode 100644 index 000000000..9cb4961e6 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/ExamRepository.kt @@ -0,0 +1,39 @@ +package io.github.wulkanowy.data.repositories + +import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork +import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings +import io.github.wulkanowy.data.db.entities.Exam +import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.repositories.local.ExamLocal +import io.github.wulkanowy.data.repositories.remote.ExamRemote +import io.reactivex.Single +import org.threeten.bp.LocalDate +import java.net.UnknownHostException +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class ExamRepository @Inject constructor( + private val settings: InternetObservingSettings, + private val local: ExamLocal, + private val remote: ExamRemote +) { + + fun getExams(semester: Semester, date: LocalDate, forceRefresh: Boolean = false): Single> { + return local.getExams(semester, date).filter { !forceRefresh } + .switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings) + .flatMap { + if (it) remote.getExams(semester, date) + else Single.error(UnknownHostException()) + }.flatMap { newExams -> + local.getExams(semester, date).toSingle(emptyList()) + .map { + local.deleteExams(it - newExams) + local.saveExams(newExams - it) + + newExams + } + } + ) + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/SessionRepository.kt similarity index 59% rename from app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt rename to app/src/main/java/io/github/wulkanowy/data/repositories/SessionRepository.kt index 316c482c3..6d158d29b 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/StudentRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/SessionRepository.kt @@ -2,9 +2,10 @@ package io.github.wulkanowy.data.repositories import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.InternetObservingSettings +import io.github.wulkanowy.data.db.entities.Semester import io.github.wulkanowy.data.db.entities.Student -import io.github.wulkanowy.data.repositories.local.StudentLocal -import io.github.wulkanowy.data.repositories.remote.StudentRemote +import io.github.wulkanowy.data.repositories.local.SessionLocal +import io.github.wulkanowy.data.repositories.remote.SessionRemote import io.reactivex.Completable import io.reactivex.Single import java.net.UnknownHostException @@ -12,17 +13,17 @@ import javax.inject.Inject import javax.inject.Singleton @Singleton -class StudentRepository @Inject constructor( - private val local: StudentLocal, - private val remote: StudentRemote, +class SessionRepository @Inject constructor( + private val local: SessionLocal, + private val remote: SessionRemote, private val settings: InternetObservingSettings) { + val isSessionSaved + get() = local.isSessionSaved + lateinit var cachedStudents: Single> private set - val isStudentLoggedIn: Boolean - get() = local.isStudentLoggedIn - fun getConnectedStudents(email: String, password: String, symbol: String): Single> { cachedStudents = ReactiveNetwork.checkInternetConnectivity(settings) .flatMap { isConnected -> @@ -32,9 +33,19 @@ class StudentRepository @Inject constructor( return cachedStudents } - fun save(student: Student): Completable = local.save(student) + fun getSemesters(): Single> { + return local.getLastStudent() + .flatMapSingle { + remote.initApi(it, true) + local.getSemesters(it) + } + } - fun getCurrentStudent(): Single = local.getCurrentStudent() + fun saveStudent(student: Student): Completable { + return remote.getSemesters(student).flatMapCompletable { + local.saveSemesters(it) + }.concatWith(local.saveStudent(student)) + } fun clearCache() { cachedStudents = Single.just(emptyList()) diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/local/ExamLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/local/ExamLocal.kt new file mode 100644 index 000000000..2ca12411d --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/local/ExamLocal.kt @@ -0,0 +1,28 @@ +package io.github.wulkanowy.data.repositories.local + +import io.github.wulkanowy.data.db.dao.ExamDao +import io.github.wulkanowy.data.db.entities.Exam +import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.utils.extension.toDate +import io.reactivex.Maybe +import org.threeten.bp.DayOfWeek +import org.threeten.bp.LocalDate +import org.threeten.bp.temporal.TemporalAdjusters +import javax.inject.Inject + +class ExamLocal @Inject constructor(private val examDb: ExamDao) { + + fun getExams(semester: Semester, startDate: LocalDate): Maybe> { + return examDb.getExams(semester.diaryId, semester.studentId, startDate.toDate(), + startDate.with(TemporalAdjusters.next(DayOfWeek.FRIDAY)).toDate() + ).filter { !it.isEmpty() } + } + + fun saveExams(exams: List) { + examDb.insertAll(exams) + } + + fun deleteExams(exams: List) { + examDb.deleteAll(exams) + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/local/SessionLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/local/SessionLocal.kt new file mode 100644 index 000000000..e507899a6 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/local/SessionLocal.kt @@ -0,0 +1,49 @@ +package io.github.wulkanowy.data.repositories.local + +import android.content.Context +import io.github.wulkanowy.data.db.SharedPrefHelper +import io.github.wulkanowy.data.db.dao.SemesterDao +import io.github.wulkanowy.data.db.dao.StudentDao +import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student +import io.github.wulkanowy.utils.security.Scrambler.decrypt +import io.github.wulkanowy.utils.security.Scrambler.encrypt +import io.reactivex.Completable +import io.reactivex.Maybe +import io.reactivex.Single +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class SessionLocal @Inject constructor( + private val studentDb: StudentDao, + private val semesterDb: SemesterDao, + private val sharedPref: SharedPrefHelper, + private val context: Context) { + + companion object { + const val LAST_USER_KEY: String = "last_user_id" + } + + val isSessionSaved + get() = sharedPref.getLong(LAST_USER_KEY, defaultValue = 0L) != 0L + + fun saveStudent(student: Student): Completable { + return Single.fromCallable { studentDb.insert(student.copy(password = encrypt(student.password, context))) } + .map { sharedPref.putLong(LAST_USER_KEY, it) } + .ignoreElement() + } + + fun getLastStudent(): Maybe { + return studentDb.load(sharedPref.getLong(LAST_USER_KEY, defaultValue = 0)) + .map { it.apply { password = decrypt(password) } } + } + + fun saveSemesters(semesters: List): Completable { + return Single.fromCallable { semesterDb.insertAll(semesters) }.ignoreElement() + } + + fun getSemesters(student: Student): Single> { + return semesterDb.getSemester(student.studentId) + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/local/StudentLocal.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/local/StudentLocal.kt deleted file mode 100644 index a500141c3..000000000 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/local/StudentLocal.kt +++ /dev/null @@ -1,37 +0,0 @@ -package io.github.wulkanowy.data.repositories.local - -import android.content.Context -import io.github.wulkanowy.data.db.SharedPrefHelper -import io.github.wulkanowy.data.db.dao.StudentDao -import io.github.wulkanowy.data.db.entities.Student -import io.github.wulkanowy.utils.security.Scrambler.decrypt -import io.github.wulkanowy.utils.security.Scrambler.encrypt -import io.reactivex.Completable -import io.reactivex.Single -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class StudentLocal @Inject constructor( - private val studentDb: StudentDao, - private val sharedPref: SharedPrefHelper, - private val context: Context) { - - companion object { - const val CURRENT_USER_KEY: String = "current_user_id" - } - - val isStudentLoggedIn: Boolean - get() = sharedPref.getLong(CURRENT_USER_KEY, 0) != 0L - - fun save(student: Student): Completable { - return Single.fromCallable { studentDb.insert(student.copy(password = encrypt(student.password, context))) } - .map { sharedPref.putLong(CURRENT_USER_KEY, it) } - .ignoreElement() - } - - fun getCurrentStudent(): Single { - return studentDb.load(sharedPref.getLong(CURRENT_USER_KEY, defaultValue = 0)) - .map { it.apply { password = decrypt(password) } } - } -} diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/ExamRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/remote/ExamRemote.kt new file mode 100644 index 000000000..df179afd5 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/remote/ExamRemote.kt @@ -0,0 +1,37 @@ +package io.github.wulkanowy.data.repositories.remote + +import io.github.wulkanowy.api.Api +import io.github.wulkanowy.data.db.entities.Exam +import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.utils.extension.toDate +import io.reactivex.Single +import org.threeten.bp.LocalDate +import javax.inject.Inject + +class ExamRemote @Inject constructor(private val api: Api) { + + fun getExams(semester: Semester, startDate: LocalDate): Single> { + return Single.just(api.run { + if (diaryId != semester.diaryId) { + diaryId = semester.diaryId + notifyDataChanged() + } + }).flatMap { api.getExams(startDate.toDate()) } + .map { exams -> + exams.map { + Exam( + studentId = semester.studentId, + diaryId = semester.diaryId, + date = it.date, + entryDate = it.entryDate, + subject = it.subject, + group = it.group, + type = it.type, + description = it.description, + teacher = it.teacher, + teacherSymbol = it.teacherSymbol + ) + } + } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/SessionRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/remote/SessionRemote.kt new file mode 100644 index 000000000..8fdb86325 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/remote/SessionRemote.kt @@ -0,0 +1,59 @@ +package io.github.wulkanowy.data.repositories.remote + +import io.github.wulkanowy.api.Api +import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student +import io.reactivex.Single +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class SessionRemote @Inject constructor(private val api: Api) { + + fun getConnectedStudents(email: String, password: String, symbol: String): Single> { + return Single.just(initApi(Student(email = email, password = password, symbol = symbol))) + .flatMap { _ -> + api.getPupils().map { students -> + students.map { + Student(email = email, + password = password, + symbol = it.symbol, + studentId = it.studentId, + studentName = it.studentName, + schoolId = it.schoolId, + schoolName = it.schoolName) + } + } + } + } + + fun getSemesters(student: Student): Single> { + return Single.just(initApi(student)).flatMap { _ -> + api.getSemesters().map { semesters -> + semesters.map { + Semester(studentId = student.studentId, + diaryId = it.diaryId, + diaryName = it.diaryName, + semesterId = it.semesterId.toString(), + semesterName = it.semesterNumber, + current = it.current) + } + + } + } + } + + fun initApi(student: Student, checkInit: Boolean = false) { + if (if (checkInit) api.studentId.isEmpty() else true) { + api.run { + email = student.email + password = student.password + symbol = student.symbol + host = "vulcan.net.pl" + schoolId = student.schoolId + studentId = student.studentId + notifyDataChanged() + } + } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/StudentRemote.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/remote/StudentRemote.kt deleted file mode 100644 index 02b447232..000000000 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/remote/StudentRemote.kt +++ /dev/null @@ -1,32 +0,0 @@ -package io.github.wulkanowy.data.repositories.remote - -import io.github.wulkanowy.api.Api -import io.github.wulkanowy.data.db.entities.Student -import io.reactivex.Single -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class StudentRemote @Inject constructor(private val api: Api) { - - fun getConnectedStudents(email: String, password: String, symbol: String): Single> { - api.let { - it.email = email - it.password = password - it.symbol = symbol - it.host = "vulcan.net.pl" - it.onConfigChange() - } - return api.getPupils().map { students -> - students.map { - Student(email = email, - password = password, - symbol = it.symbol, - studentId = it.studentId, - studentName = it.studentName, - schoolId = it.schoolId, - schoolName = it.schoolName) - } - } - } -} diff --git a/app/src/main/java/io/github/wulkanowy/di/AppModule.kt b/app/src/main/java/io/github/wulkanowy/di/AppModule.kt index 612f837f6..6eff9e971 100644 --- a/app/src/main/java/io/github/wulkanowy/di/AppModule.kt +++ b/app/src/main/java/io/github/wulkanowy/di/AppModule.kt @@ -3,8 +3,9 @@ package io.github.wulkanowy.di import android.content.Context import dagger.Module import dagger.Provides +import eu.davidea.flexibleadapter.FlexibleAdapter +import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.WulkanowyApp -import io.github.wulkanowy.data.ErrorHandler import io.github.wulkanowy.utils.schedulers.SchedulersManager import io.github.wulkanowy.utils.schedulers.SchedulersProvider @@ -18,5 +19,5 @@ internal class AppModule { fun provideSchedulers(): SchedulersManager = SchedulersProvider() @Provides - fun provideErrorHandler(context: Context): ErrorHandler = ErrorHandler(context.resources) + fun provideFlexibleAdapter() = FlexibleAdapter>(null, null, true) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/form/LoginFormPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/login/form/LoginFormPresenter.kt index 27ddb5409..3cc25a84d 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/form/LoginFormPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/login/form/LoginFormPresenter.kt @@ -1,6 +1,6 @@ package io.github.wulkanowy.ui.login.form -import io.github.wulkanowy.data.repositories.StudentRepository +import io.github.wulkanowy.data.repositories.SessionRepository import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.ui.login.LoginErrorHandler import io.github.wulkanowy.utils.DEFAULT_SYMBOL @@ -10,7 +10,7 @@ import javax.inject.Inject class LoginFormPresenter @Inject constructor( private val schedulers: SchedulersManager, private val errorHandler: LoginErrorHandler, - private val studentRepository: StudentRepository) + private val sessionRepository: SessionRepository) : BasePresenter(errorHandler) { private var wasEmpty = false @@ -22,7 +22,7 @@ class LoginFormPresenter @Inject constructor( fun attemptLogin(email: String, password: String, symbol: String) { if (!validateCredentials(email, password, symbol)) return - disposable.add(studentRepository.getConnectedStudents(email, password, normalizeSymbol(symbol)) + disposable.add(sessionRepository.getConnectedStudents(email, password, normalizeSymbol(symbol)) .observeOn(schedulers.mainThread()) .subscribeOn(schedulers.backgroundThread()) .doOnSubscribe { @@ -34,7 +34,7 @@ class LoginFormPresenter @Inject constructor( showSoftKeyboard() } } - studentRepository.clearCache() + sessionRepository.clearCache() } .doFinally { view?.showLoginProgress(false) } .subscribe({ diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/options/LoginOptionsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/login/options/LoginOptionsFragment.kt index 382f9f47b..cedf47f6e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/options/LoginOptionsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/login/options/LoginOptionsFragment.kt @@ -9,6 +9,7 @@ import android.view.View.VISIBLE import android.view.ViewGroup import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager +import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.R import io.github.wulkanowy.ui.base.BaseFragment import io.github.wulkanowy.ui.main.MainActivity @@ -22,7 +23,11 @@ class LoginOptionsFragment : BaseFragment(), LoginOptionsView { lateinit var presenter: LoginOptionsPresenter @Inject - lateinit var loginAdapter: FlexibleAdapter + lateinit var loginAdapter: FlexibleAdapter> + + companion object { + fun newInstance() = LoginOptionsFragment() + } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_login_options, container, false) @@ -34,7 +39,13 @@ class LoginOptionsFragment : BaseFragment(), LoginOptionsView { } override fun initRecycler() { - loginAdapter.setOnItemClickListener { item -> item?.let { presenter.onSelectStudent(it.student) } } + loginAdapter.run { + setOnItemClickListener { position -> + (getItem(position) as? LoginOptionsItem)?.let { + presenter.onSelectStudent(it.student) + } + } + } loginOptionsRecycler.run { adapter = loginAdapter layoutManager = SmoothScrollLinearLayoutManager(context) @@ -47,7 +58,7 @@ class LoginOptionsFragment : BaseFragment(), LoginOptionsView { override fun updateData(data: List) { loginAdapter.run { - updateDataSet(data) + updateDataSet(data, true) } } @@ -66,4 +77,9 @@ class LoginOptionsFragment : BaseFragment(), LoginOptionsView { override fun showActionBar(show: Boolean) { (activity as AppCompatActivity?)?.supportActionBar?.run { if (show) show() else hide() } } + + override fun onDestroyView() { + super.onDestroyView() + presenter.detachView() + } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/options/LoginOptionsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/login/options/LoginOptionsPresenter.kt index 3221cf51a..3fb3c13d4 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/options/LoginOptionsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/login/options/LoginOptionsPresenter.kt @@ -2,14 +2,14 @@ package io.github.wulkanowy.ui.login.options import io.github.wulkanowy.data.ErrorHandler import io.github.wulkanowy.data.db.entities.Student -import io.github.wulkanowy.data.repositories.StudentRepository +import io.github.wulkanowy.data.repositories.SessionRepository import io.github.wulkanowy.ui.base.BasePresenter import io.github.wulkanowy.utils.schedulers.SchedulersManager import javax.inject.Inject class LoginOptionsPresenter @Inject constructor( private val errorHandler: ErrorHandler, - private val repository: StudentRepository, + private val repository: SessionRepository, private val schedulers: SchedulersManager) : BasePresenter(errorHandler) { @@ -32,7 +32,7 @@ class LoginOptionsPresenter @Inject constructor( } fun onSelectStudent(student: Student) { - disposable.add(repository.save(student) + disposable.add(repository.saveStudent(student) .subscribeOn(schedulers.backgroundThread()) .observeOn(schedulers.mainThread()) .doOnSubscribe { _ -> diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamDialog.kt new file mode 100644 index 000000000..7f15267d4 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamDialog.kt @@ -0,0 +1,51 @@ +package io.github.wulkanowy.ui.main.exam + +import android.os.Bundle +import android.support.v4.app.DialogFragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import io.github.wulkanowy.R +import io.github.wulkanowy.data.db.entities.Exam +import io.github.wulkanowy.utils.extension.toFormat +import kotlinx.android.synthetic.main.dialog_exam.* + +class ExamDialog : DialogFragment() { + + private lateinit var exam: Exam + + companion object { + private const val ARGUMENT_KEY = "Item" + + fun newInstance(exam: Exam): ExamDialog { + return ExamDialog().apply { + arguments = Bundle().apply { putSerializable(ARGUMENT_KEY, exam) } + } + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setStyle(DialogFragment.STYLE_NORMAL, R.style.DialogFragmentTheme) + arguments?.run { + exam = getSerializable(ARGUMENT_KEY) as Exam + } + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + dialog.setTitle(getString(R.string.all_details)) + return inflater.inflate(R.layout.dialog_exam, container, false) + } + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + + examDialogSubjectValue.text = exam.subject + examDialogTypeValue.text = exam.type + examDialogTeacherValue.text = exam.teacher + examDialogDateValue.text = exam.entryDate.toFormat() + examDialogDescriptionValue.text = exam.description + + examDialogClose.setOnClickListener { dismiss() } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamFragment.kt index ca60fe888..957bb94f8 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamFragment.kt @@ -3,17 +3,104 @@ package io.github.wulkanowy.ui.main.exam import android.os.Bundle import android.view.LayoutInflater import android.view.View +import android.view.View.* import android.view.ViewGroup +import eu.davidea.flexibleadapter.FlexibleAdapter +import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager +import eu.davidea.flexibleadapter.items.AbstractFlexibleItem import io.github.wulkanowy.R +import io.github.wulkanowy.data.db.entities.Exam import io.github.wulkanowy.ui.base.BaseFragment +import io.github.wulkanowy.utils.extension.setOnItemClickListener +import kotlinx.android.synthetic.main.fragment_exam.* +import javax.inject.Inject -class ExamFragment : BaseFragment() { +class ExamFragment : BaseFragment(), ExamView { + + @Inject + lateinit var presenter: ExamPresenter + + @Inject + lateinit var examAdapter: FlexibleAdapter> companion object { + private const val SAVED_DATE_KEY = "CURRENT_DATE" fun newInstance() = ExamFragment() } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_exam, container, false) } + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + presenter.run { + attachView(this@ExamFragment) + loadData(date = savedInstanceState?.getLong(SAVED_DATE_KEY)) + } + } + + override fun initView() { + examAdapter.run { + setOnItemClickListener { presenter.onExamItemSelected(getItem(it)) } + } + examRecycler.run { + layoutManager = SmoothScrollLinearLayoutManager(context) + adapter = examAdapter + } + examSwipe.setOnRefreshListener { presenter.loadData(date = null, forceRefresh = true) } + examPreviousButton.setOnClickListener { presenter.loadExamsForPreviousWeek() } + examNextButton.setOnClickListener { presenter.loadExamsForNextWeek()} + } + + override fun updateData(data: List) { + examAdapter.updateDataSet(data, true) + } + + override fun updateNavigationWeek(date: String) { + examNavDate.text = date + } + + override fun showEmpty(show: Boolean) { + examEmpty.visibility = if (show) VISIBLE else GONE + } + + override fun showProgress(show: Boolean) { + examProgress.visibility = if (show) VISIBLE else GONE + } + + override fun showContent(show: Boolean) { + examRecycler.visibility = if (show) VISIBLE else GONE + } + + override fun showRefresh(show: Boolean) { + examSwipe.isRefreshing = show + } + + override fun showPreButton(show: Boolean) { + examPreviousButton.visibility = if (show) VISIBLE else INVISIBLE + } + + override fun showNextButton(show: Boolean) { + examNextButton.visibility = if (show) VISIBLE else INVISIBLE + } + + override fun showExamDialog(exam: Exam) { + ExamDialog.newInstance(exam).show(fragmentManager, exam.toString()) + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + outState.putLong(SAVED_DATE_KEY, presenter.currentDate.toEpochDay()) + } + + override fun onViewStateRestored(savedInstanceState: Bundle?) { + super.onViewStateRestored(savedInstanceState) + presenter.loadData(date = savedInstanceState?.getLong(SAVED_DATE_KEY)) + } + + override fun onDestroyView() { + super.onDestroyView() + presenter.detachView() + } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamHeader.kt b/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamHeader.kt new file mode 100644 index 000000000..fce271721 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamHeader.kt @@ -0,0 +1,59 @@ +package io.github.wulkanowy.ui.main.exam + +import android.view.View +import eu.davidea.flexibleadapter.FlexibleAdapter +import eu.davidea.flexibleadapter.items.AbstractHeaderItem +import eu.davidea.flexibleadapter.items.IFlexible +import eu.davidea.viewholders.ExpandableViewHolder +import io.github.wulkanowy.R +import io.github.wulkanowy.utils.extension.getWeekDayName +import io.github.wulkanowy.utils.extension.toFormat +import kotlinx.android.extensions.LayoutContainer +import kotlinx.android.synthetic.main.header_exam.* +import org.apache.commons.lang3.StringUtils +import java.util.* + +class ExamHeader : AbstractHeaderItem() { + + lateinit var date: Date + + override fun createViewHolder(view: View?, adapter: FlexibleAdapter>?): ViewHolder { + return ViewHolder(view, adapter) + } + + override fun getLayoutRes() = R.layout.header_exam + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as ExamHeader + + if (date != other.date) return false + + return true + } + + override fun hashCode(): Int { + return date.hashCode() + } + + override fun bindViewHolder(adapter: FlexibleAdapter>?, holder: ViewHolder, + position: Int, payloads: MutableList?) { + holder.run { + examHeaderDay.text = StringUtils.capitalize(date.getWeekDayName()) + examHeaderDate.text = date.toFormat() + } + } + + class ViewHolder(view: View?, adapter: FlexibleAdapter>?) : ExpandableViewHolder(view, adapter), + LayoutContainer { + + init { + contentView.setOnClickListener(this) + } + + override val containerView: View + get() = contentView + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamItem.kt b/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamItem.kt new file mode 100644 index 000000000..bb7a503de --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamItem.kt @@ -0,0 +1,52 @@ +package io.github.wulkanowy.ui.main.exam + +import android.support.v7.widget.RecyclerView +import android.view.View +import eu.davidea.flexibleadapter.FlexibleAdapter +import eu.davidea.flexibleadapter.items.AbstractSectionableItem +import eu.davidea.flexibleadapter.items.IFlexible +import eu.davidea.viewholders.FlexibleViewHolder +import io.github.wulkanowy.R +import io.github.wulkanowy.data.db.entities.Exam +import kotlinx.android.extensions.LayoutContainer +import kotlinx.android.synthetic.main.item_exam.* + +class ExamItem(header: ExamHeader, val exam: Exam) : AbstractSectionableItem(header) { + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as ExamItem + + if (exam != other.exam) return false + + return true + } + + override fun hashCode(): Int { + return exam.hashCode() + } + + override fun getLayoutRes() = R.layout.item_exam + + override fun createViewHolder(view: View, adapter: FlexibleAdapter>): ViewHolder { + return ViewHolder(view, adapter) + } + + override fun bindViewHolder(adapter: FlexibleAdapter>, holder: ViewHolder, + position: Int, payloads: MutableList?) { + holder.run { + examItemSubject.text = exam.subject + examItemTeacher.text = exam.teacher + examItemType.text = exam.type + } + } + + class ViewHolder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter), + LayoutContainer { + + override val containerView: View + get() = contentView + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamPresenter.kt new file mode 100644 index 000000000..f00a07983 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamPresenter.kt @@ -0,0 +1,98 @@ +package io.github.wulkanowy.ui.main.exam + +import eu.davidea.flexibleadapter.items.AbstractFlexibleItem +import io.github.wulkanowy.data.ErrorHandler +import io.github.wulkanowy.data.db.entities.Exam +import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.repositories.ExamRepository +import io.github.wulkanowy.data.repositories.SessionRepository +import io.github.wulkanowy.ui.base.BasePresenter +import io.github.wulkanowy.utils.extension.isHolidays +import io.github.wulkanowy.utils.extension.toFormat +import io.github.wulkanowy.utils.getNearMonday +import io.github.wulkanowy.utils.schedulers.SchedulersManager +import org.threeten.bp.LocalDate +import java.util.* +import javax.inject.Inject + +class ExamPresenter @Inject constructor( + private val errorHandler: ErrorHandler, + private val schedulers: SchedulersManager, + private val examRepository: ExamRepository, + private val sessionRepository: SessionRepository +) : BasePresenter(errorHandler) { + + var currentDate: LocalDate = getNearMonday(LocalDate.now()) + private set + + override fun attachView(view: ExamView) { + super.attachView(view) + view.initView() + } + + fun loadExamsForPreviousWeek() = loadData(currentDate.minusDays(7).toEpochDay()) + + fun loadExamsForNextWeek() = loadData(currentDate.plusDays(7).toEpochDay()) + + fun loadData(date: Long?, forceRefresh: Boolean = false) { + this.currentDate = LocalDate.ofEpochDay(date ?: getNearMonday(currentDate).toEpochDay()) + if (currentDate.isHolidays()) return + + disposable.clear() + disposable.add(sessionRepository.getSemesters() + .map { selectSemester(it, -1) } + .flatMap { examRepository.getExams(it, currentDate, forceRefresh) } + .map { it.groupBy { exam -> exam.date }.toSortedMap() } + .map { createExamItems(it) } + .subscribeOn(schedulers.backgroundThread()) + .observeOn(schedulers.mainThread()) + .doOnSubscribe { + view?.run { + showRefresh(forceRefresh) + showProgress(!forceRefresh) + if (!forceRefresh) showEmpty(false) + showContent(null == date && forceRefresh) + showPreButton(!currentDate.minusDays(7).isHolidays()) + showNextButton(!currentDate.plusDays(7).isHolidays()) + updateNavigationWeek("${currentDate.toFormat("dd.MM")}-${currentDate.plusDays(4).toFormat("dd.MM")}") + } + } + .doAfterSuccess { + view?.run { + showEmpty(it.isEmpty()) + showContent(it.isNotEmpty()) + } + } + .doFinally { + view?.run { + showRefresh(false) + showProgress(false) + } + } + .subscribe({ view?.updateData(it) }) { errorHandler.proceed(it) }) + } + + private fun createExamItems(items: Map>): List { + return items.flatMap { + val header = ExamHeader().apply { date = it.key } + it.value.reversed().map { item -> + ExamItem(header, item) + } + } + } + + fun onExamItemSelected(item: AbstractFlexibleItem<*>?) { + if (item is ExamItem) view?.showExamDialog(item.exam) + } + + private fun selectSemester(semesters: List, index: Int): Semester { + return semesters.single { it.current }.let { currentSemester -> + if (index == -1) currentSemester + else semesters.single { semester -> + semester.run { + semesterName - 1 == index && diaryId == currentSemester.diaryId + } + } + } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamView.kt b/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamView.kt new file mode 100644 index 000000000..64ee9517a --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exam/ExamView.kt @@ -0,0 +1,28 @@ +package io.github.wulkanowy.ui.main.exam + +import io.github.wulkanowy.data.db.entities.Exam +import io.github.wulkanowy.ui.base.BaseView +import org.threeten.bp.LocalDate + +interface ExamView : BaseView { + + fun initView() + + fun updateData(data: List) + + fun showEmpty(show: Boolean) + + fun showProgress(show: Boolean) + + fun showContent(show: Boolean) + + fun showRefresh(show: Boolean) + + fun showNextButton(show: Boolean) + + fun showPreButton(show: Boolean) + + fun showExamDialog(exam: Exam) + + fun updateNavigationWeek(date: String) +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.kt index 6ea0ff0f0..f3cf93d9e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.kt @@ -21,12 +21,12 @@ class SplashActivity : BaseActivity(), SplashView { presenter.detachView() } - override fun openLoginActivity() { + override fun openLoginView() { startActivity(LoginActivity.getStartIntent(this)) finish() } - override fun openMainActivity() { + override fun openMainView() { startActivity(MainActivity.getStartIntent(this)) finish() } diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.kt index ba69ecbc3..0a22284c7 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashPresenter.kt @@ -1,16 +1,16 @@ package io.github.wulkanowy.ui.splash import io.github.wulkanowy.data.ErrorHandler -import io.github.wulkanowy.data.repositories.StudentRepository +import io.github.wulkanowy.data.repositories.SessionRepository import io.github.wulkanowy.ui.base.BasePresenter import javax.inject.Inject -class SplashPresenter @Inject constructor(private val studentRepository: StudentRepository, +class SplashPresenter @Inject constructor(private val sessionRepository: SessionRepository, errorHandler: ErrorHandler) : BasePresenter(errorHandler) { override fun attachView(view: SplashView) { super.attachView(view) - view.run { if (studentRepository.isStudentLoggedIn) openMainActivity() else openLoginActivity() } + view.run { if (sessionRepository.isSessionSaved) openMainView() else openLoginView() } } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashView.kt b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashView.kt index 7cdde3b3a..340739334 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashView.kt @@ -4,7 +4,7 @@ import io.github.wulkanowy.ui.base.BaseView interface SplashView : BaseView { - fun openLoginActivity() + fun openLoginView() - fun openMainActivity() + fun openMainView() } diff --git a/app/src/main/java/io/github/wulkanowy/utils/TimeUtils.kt b/app/src/main/java/io/github/wulkanowy/utils/TimeUtils.kt index dc45d87df..bb9bebf33 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/TimeUtils.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/TimeUtils.kt @@ -4,6 +4,7 @@ import org.threeten.bp.DayOfWeek.* import org.threeten.bp.LocalDate import org.threeten.bp.Year import org.threeten.bp.format.DateTimeFormatter +import org.threeten.bp.temporal.TemporalAdjuster import org.threeten.bp.temporal.TemporalAdjusters import java.util.* @@ -68,29 +69,35 @@ fun isDateInWeek(firstWeekDay: LocalDate, date: LocalDate): Boolean { return date.isAfter(firstWeekDay.minusDays(1)) && date.isBefore(firstWeekDay.plusDays(5)) } +fun getNearMonday(date: LocalDate): LocalDate { + return when(date.dayOfWeek) { + MONDAY -> date + SATURDAY, SUNDAY -> date.with(TemporalAdjusters.next(MONDAY)) + else -> date.with(TemporalAdjusters.previous(MONDAY)) + } +} + /** * [Dz.U. 2016 poz. 1335](http://prawo.sejm.gov.pl/isap.nsf/DocDetails.xsp?id=WDU20160001335) */ -fun isHolidays(): Boolean = isHolidays(LocalDate.now(), Year.now().value) +fun isHolidays(): Boolean = isHolidays(LocalDate.now()) -fun isHolidays(day: LocalDate, year: Int): Boolean { - return day.isAfter(getLastSchoolDay(year)) && day.isBefore(getFirstSchoolDay(year)) +fun isHolidays(day: LocalDate): Boolean { + return day.isAfter(getLastSchoolDay(day.year)) && day.isBefore(getFirstSchoolDay(day.year)) } -fun getFirstSchoolDay(year: Int): LocalDate? { +fun getFirstSchoolDay(year: Int): LocalDate { val firstSeptember = LocalDate.of(year, 9, 1) return when (firstSeptember.dayOfWeek) { FRIDAY, SATURDAY, SUNDAY -> firstSeptember.with(TemporalAdjusters.firstInMonth(MONDAY)) - else -> { - firstSeptember - } + else -> firstSeptember } } -fun getLastSchoolDay(year: Int): LocalDate? { +fun getLastSchoolDay(year: Int): LocalDate { return LocalDate .of(year, 6, 20) .with(TemporalAdjusters.next(FRIDAY)) diff --git a/app/src/main/java/io/github/wulkanowy/utils/extension/DateExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/extension/DateExtension.kt new file mode 100644 index 000000000..db5965abb --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/utils/extension/DateExtension.kt @@ -0,0 +1,25 @@ +package io.github.wulkanowy.utils.extension + +import io.github.wulkanowy.utils.DATE_PATTERN +import io.github.wulkanowy.utils.isHolidays +import org.threeten.bp.Instant +import org.threeten.bp.LocalDate +import org.threeten.bp.ZoneId +import org.threeten.bp.format.DateTimeFormatter +import java.util.* + +private val formatter = DateTimeFormatter.ofPattern(DATE_PATTERN) + +fun LocalDate.toDate(): Date = java.sql.Date.valueOf(this.format(formatter)) + +fun LocalDate.toFormat(format: String): String = this.format(DateTimeFormatter.ofPattern(format)) + +fun LocalDate.toFormat(): String = this.toFormat(DATE_PATTERN) + +fun LocalDate.isHolidays(): Boolean = isHolidays(this) + +fun Date.toLocalDate(): LocalDate = Instant.ofEpochMilli(this.time).atZone(ZoneId.systemDefault()).toLocalDate() + +fun Date.getWeekDayName(): String = this.toLocalDate().format(DateTimeFormatter.ofPattern("EEEE", Locale.getDefault())) + +fun Date.toFormat(): String = this.toLocalDate().toFormat() diff --git a/app/src/main/java/io/github/wulkanowy/utils/extension/FlexibleAdapterExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/extension/FlexibleAdapterExtension.kt index 779a66fd7..b89060035 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/extension/FlexibleAdapterExtension.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/extension/FlexibleAdapterExtension.kt @@ -3,9 +3,13 @@ package io.github.wulkanowy.utils.extension import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.items.AbstractFlexibleItem -fun , T : FlexibleAdapter> T.setOnItemClickListener(listener: (K?) -> Unit) { +fun FlexibleAdapter<*>.setOnItemClickListener(listener: (position: Int) -> Unit) { addListener(FlexibleAdapter.OnItemClickListener { _, position -> - listener(getItem(position)) + listener(position) true }) } + +fun FlexibleAdapter<*>.setOnUpdateListener(listener: (size: Int) -> Unit) { + addListener(FlexibleAdapter.OnUpdateListener { listener(it) }) +} diff --git a/app/src/main/res/layout/dialog_exam.xml b/app/src/main/res/layout/dialog_exam.xml index e59956ef8..a15626600 100644 --- a/app/src/main/res/layout/dialog_exam.xml +++ b/app/src/main/res/layout/dialog_exam.xml @@ -1,6 +1,5 @@ @@ -8,171 +7,106 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:minWidth="300dp" - android:orientation="vertical"> + android:orientation="vertical" + android:padding="20dp"> - + android:text="@string/all_subject" + android:textIsSelectable="true" + android:textSize="17sp" /> - + - + - + - + - + - + - + - + - + - +