Merge branch 'release/0.9.2'

This commit is contained in:
Rafał Borcz 2019-06-08 11:38:42 +02:00
commit 5c185c5eca
25 changed files with 229 additions and 109 deletions

View File

@ -11,9 +11,10 @@ cache:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
#branches:
# only:
# - develop
branches:
only:
- develop
- 0.9.2
android:
licenses:

View File

@ -17,8 +17,8 @@ android {
testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 15
targetSdkVersion 28
versionCode 39
versionName "0.9.1"
versionCode 40
versionName "0.9.2"
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
@ -98,18 +98,23 @@ play {
}
dependencies {
implementation 'io.github.wulkanowy:api:0.9.1'
implementation "io.github.wulkanowy:api:0.9.2"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "androidx.legacy:legacy-support-v4:1.0.0"
implementation "androidx.core:core:1.0.2"
implementation "androidx.appcompat:appcompat:1.0.2"
implementation 'androidx.multidex:multidex:2.0.1'
implementation "androidx.fragment:fragment:1.0.0"
implementation "androidx.annotation:annotation:1.1.0"
implementation "androidx.multidex:multidex:2.0.1"
implementation "androidx.cardview:cardview:1.0.0"
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation "com.google.android.material:material:1.1.0-alpha05"
implementation 'com.github.wulkanowy:MaterialChipsInput:b72fd0ee6f'
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
implementation "androidx.recyclerview:recyclerview:1.0.0"
implementation "androidx.viewpager:viewpager:1.0.0"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
implementation "androidx.constraintlayout:constraintlayout:1.1.3"
implementation "androidx.coordinatorlayout:coordinatorlayout:1.0.0"
implementation "com.google.android.material:material:1.1.0-alpha07"
implementation "com.github.wulkanowy:MaterialChipsInput:b72fd0ee6f"
implementation "com.github.PhilJay:MPAndroidChart:v3.1.0"
implementation "androidx.work:work-runtime:2.0.1"
implementation "androidx.work:work-rxjava2:2.0.1"
@ -121,51 +126,51 @@ dependencies {
implementation "com.google.dagger:dagger-android-support:2.23.1"
kapt "com.google.dagger:dagger-compiler:2.23.1"
kapt "com.google.dagger:dagger-android-processor:2.23.1"
implementation 'com.squareup.inject:assisted-inject-annotations-dagger2:0.4.0'
kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.4.0'
implementation "com.squareup.inject:assisted-inject-annotations-dagger2:0.4.0"
kapt "com.squareup.inject:assisted-inject-processor-dagger2:0.4.0"
implementation "eu.davidea:flexible-adapter:5.1.0"
implementation "eu.davidea:flexible-adapter-ui:1.0.0"
implementation "com.aurelhubert:ahbottomnavigation:2.3.4"
implementation 'com.ncapdevi:frag-nav:3.2.0'
implementation "com.ncapdevi:frag-nav:3.2.0"
implementation 'com.github.pwittchen:reactivenetwork-rx2:3.0.3'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation "com.github.pwittchen:reactivenetwork-rx2:3.0.3"
implementation "io.reactivex.rxjava2:rxandroid:2.1.1"
implementation "io.reactivex.rxjava2:rxjava:2.2.9"
implementation 'com.google.code.gson:gson:2.8.5'
implementation "com.jakewharton.threetenabp:threetenabp:1.2.0"
implementation "com.google.code.gson:gson:2.8.5"
implementation "com.jakewharton.threetenabp:threetenabp:1.2.1"
implementation "com.jakewharton.timber:timber:4.7.1"
implementation "at.favre.lib:slf4j-timber:1.0.1"
implementation "com.squareup.okhttp3:logging-interceptor:3.12.3"
implementation "com.mikepenz:aboutlibraries:6.2.3"
implementation 'com.takisoft.preferencex:preferencex:1.0.0'
implementation "com.takisoft.preferencex:preferencex:1.0.0"
playImplementation 'com.google.firebase:firebase-core:16.0.9'
playImplementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
playImplementation "com.google.firebase:firebase-core:16.0.9"
playImplementation "com.crashlytics.sdk.android:crashlytics:2.10.1"
releaseImplementation 'fr.o80.chucker:library-no-op:2.0.4'
releaseImplementation "fr.o80.chucker:library-no-op:2.0.4"
debugImplementation 'fr.o80.chucker:library:2.0.4'
debugImplementation "fr.o80.chucker:library:2.0.4"
debugImplementation "com.amitshekhar.android:debug-db:1.0.6"
testImplementation "junit:junit:4.12"
testImplementation "io.mockk:mockk:1.9.2"
testImplementation 'org.threeten:threetenbp:1.4.0'
testImplementation "org.threeten:threetenbp:1.4.0"
testImplementation "org.mockito:mockito-core:2.28.2"
testImplementation("org.mockito:mockito-inline:2.28.2") {
exclude group: 'org.mockito', module: 'mockito-core'
exclude group: "org.mockito", module: "mockito-core"
}
androidTestImplementation 'androidx.test:core:1.2.0'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation "androidx.test:core:1.2.0"
androidTestImplementation "androidx.test:runner:1.2.0"
androidTestImplementation "androidx.test.ext:junit:1.1.1"
androidTestImplementation "io.mockk:mockk-android:1.9.2"
androidTestImplementation "androidx.room:room-testing:2.1.0-rc01"
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
androidTestImplementation "org.mockito:mockito-core:2.28.2"
androidTestImplementation('org.mockito:mockito-android:2.28.2') {
androidTestImplementation("org.mockito:mockito-android:2.28.2") {
exclude group: 'org.mockito', module: 'mockito-core'
}
}

View File

@ -37,3 +37,6 @@
#Config for API
-keep class io.github.wulkanowy.api.** {*;}
#Config for Material Components
-keep class com.google.android.material.tabs.** {*;}

View File

@ -5,13 +5,13 @@ package io.github.wulkanowy.utils
import android.content.Context
import timber.log.Timber
fun initCrashlytics(context: Context, appInfo: AppInfo) {
// do nothing
}
class CrashlyticsTree : Timber.Tree() {
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
// do nothing
}
}
fun initCrashlytics(context: Context) {
// do nothing
}

View File

@ -80,7 +80,6 @@
android:name="android.appwidget.provider"
android:resource="@xml/provider_widget_timetable" />
</receiver>
<receiver
android:name=".ui.modules.luckynumberwidget.LuckyNumberWidgetProvider"
android:label="@string/lucky_number_title">

View File

@ -1,6 +1,8 @@
package io.github.wulkanowy
import android.content.Context
import android.util.Log.INFO
import android.util.Log.VERBOSE
import androidx.multidex.MultiDex
import androidx.work.Configuration
import androidx.work.WorkManager
@ -9,10 +11,10 @@ import dagger.android.AndroidInjector
import dagger.android.support.DaggerApplication
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.utils.Log
import io.github.wulkanowy.BuildConfig.DEBUG
import io.github.wulkanowy.di.DaggerAppComponent
import io.github.wulkanowy.services.sync.SyncWorkerFactory
import io.github.wulkanowy.utils.ActivityLifecycleLogger
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.CrashlyticsTree
import io.github.wulkanowy.utils.DebugLogTree
import io.github.wulkanowy.utils.initCrashlytics
@ -27,6 +29,9 @@ class WulkanowyApp : DaggerApplication() {
@Inject
lateinit var workerFactory: SyncWorkerFactory
@Inject
lateinit var appInfo: AppInfo
override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base)
MultiDex.install(this)
@ -35,15 +40,23 @@ class WulkanowyApp : DaggerApplication() {
override fun onCreate() {
super.onCreate()
AndroidThreeTen.init(this)
WorkManager.initialize(this, Configuration.Builder().setWorkerFactory(workerFactory).build())
RxJavaPlugins.setErrorHandler(::onError)
initCrashlytics(applicationContext)
initWorkManager()
initLogging()
initCrashlytics(this, appInfo)
}
private fun initWorkManager() {
WorkManager.initialize(this,
Configuration.Builder()
.setWorkerFactory(workerFactory)
.setMinimumLoggingLevel(if (appInfo.isDebug) VERBOSE else INFO)
.build())
}
private fun initLogging() {
if (DEBUG) {
if (appInfo.isDebug) {
Timber.plant(DebugLogTree())
FlexibleAdapter.enableLogs(Log.Level.DEBUG)
} else {
@ -53,8 +66,10 @@ class WulkanowyApp : DaggerApplication() {
}
private fun onError(error: Throwable) {
if (error is UndeliverableException && error.cause is IOException || error.cause is InterruptedException) {
Timber.e(error.cause, "An undeliverable error occurred")
//RxJava's too deep stack traces may cause SOE on older android devices
val cause = error.cause
if (error is UndeliverableException && cause is IOException || cause is InterruptedException || cause is StackOverflowError) {
Timber.e(cause, "An undeliverable error occurred")
} else throw error
}

View File

@ -35,10 +35,18 @@ class MobileDeviceRepository @Inject constructor(
}
fun unregisterDevice(semester: Semester, device: MobileDevice): Single<Boolean> {
return remote.unregisterDevice(semester, device)
return ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) remote.unregisterDevice(semester, device)
else Single.error(UnknownHostException())
}
}
fun getToken(semester: Semester): Single<MobileDeviceToken> {
return remote.getToken(semester)
return ReactiveNetwork.checkInternetConnectivity(settings)
.flatMap {
if (it) remote.getToken(semester)
else Single.error(UnknownHostException())
}
}
}

View File

@ -6,10 +6,9 @@ import dagger.Module
import dagger.Provides
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import io.github.wulkanowy.BuildConfig.DEBUG
import io.github.wulkanowy.WulkanowyApp
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.SchedulersProvider
import javax.inject.Named
import javax.inject.Singleton
@Module
@ -31,7 +30,6 @@ internal class AppModule {
fun provideAppWidgetManager(context: Context): AppWidgetManager = AppWidgetManager.getInstance(context)
@Singleton
@Named("isDebug")
@Provides
fun provideIsDebug() = DEBUG
fun provideAppInfo() = AppInfo()
}

View File

@ -10,30 +10,46 @@ import androidx.work.NetworkType.CONNECTED
import androidx.work.NetworkType.UNMETERED
import androidx.work.PeriodicWorkRequest
import androidx.work.WorkManager
import io.github.wulkanowy.data.db.SharedPrefHelper
import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository
import io.github.wulkanowy.services.sync.channels.DebugChannel
import io.github.wulkanowy.services.sync.channels.NewEntriesChannel
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.isHolidays
import org.threeten.bp.LocalDate.now
import timber.log.Timber
import java.util.concurrent.TimeUnit.MINUTES
import javax.inject.Inject
import javax.inject.Named
import javax.inject.Singleton
@Singleton
class SyncManager @Inject constructor(
private val workManager: WorkManager,
private val preferencesRepository: PreferencesRepository,
sharedPrefHelper: SharedPrefHelper,
newEntriesChannel: NewEntriesChannel,
debugChannel: DebugChannel,
@Named("isDebug") isDebug: Boolean
appInfo: AppInfo
) {
companion object {
private const val APP_VERSION_CODE_KEY = "app_version_code"
}
init {
if (SDK_INT >= O) newEntriesChannel.create()
if (SDK_INT >= O && isDebug) debugChannel.create()
if (now().isHolidays) stopSyncWorker()
if (SDK_INT > O) {
newEntriesChannel.create()
if (appInfo.isDebug) debugChannel.create()
}
if (sharedPrefHelper.getLong(APP_VERSION_CODE_KEY, -1L) != appInfo.versionCode.toLong()) {
startSyncWorker(true)
sharedPrefHelper.putLong(APP_VERSION_CODE_KEY, appInfo.versionCode.toLong(), true)
}
Timber.i("SyncManager was initialized")
}

View File

@ -8,10 +8,10 @@ import android.view.View
import android.view.ViewGroup
import com.mikepenz.aboutlibraries.LibsBuilder
import com.mikepenz.aboutlibraries.LibsFragmentCompat
import io.github.wulkanowy.BuildConfig
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.openInternetBrowser
import io.github.wulkanowy.utils.withOnExtraListener
import javax.inject.Inject
@ -24,6 +24,9 @@ class AboutFragment : BaseFragment(), AboutView, MainView.TitledView {
@Inject
lateinit var fragmentCompat: LibsFragmentCompat
@Inject
lateinit var appInfo: AppInfo
companion object {
fun newInstance() = AboutFragment()
}
@ -71,9 +74,9 @@ class AboutFragment : BaseFragment(), AboutView, MainView.TitledView {
putExtra(Intent.EXTRA_EMAIL, Array(1) { "wulkanowyinc@gmail.com" })
putExtra(Intent.EXTRA_SUBJECT, "Zgłoszenie błędu")
putExtra(Intent.EXTRA_TEXT, "Tu umieść treść zgłoszenia\n\n" + "-".repeat(40) + "\n" + """
Build: ${BuildConfig.VERSION_CODE}
SDK: ${android.os.Build.VERSION.SDK_INT}
Device: ${android.os.Build.MANUFACTURER} ${android.os.Build.MODEL}
Build: ${appInfo.versionCode}
SDK: ${appInfo.systemVersion}
Device: ${appInfo.systemManufacturer} ${appInfo.systemModel}
""".trimIndent())
}

View File

@ -113,7 +113,7 @@ class GradeDetailsPresenter @Inject constructor(
.flatMap { (student, semesters) ->
averageProvider.getGradeAverage(student, semesters, semesterId, forceRefresh)
.flatMap { averages ->
gradeRepository.getGrades(student, semesters.first { semester -> semester.semesterId == semesterId })
gradeRepository.getGrades(student, semesters.first { it.semesterId == semesterId }, forceRefresh)
.map { it.sortedByDescending { grade -> grade.date } }
.map { it.groupBy { grade -> grade.subject }.toSortedMap() }
.map { createGradeItems(it, averages) }

View File

@ -10,11 +10,11 @@ import android.view.ViewGroup
import android.view.inputmethod.EditorInfo.IME_ACTION_DONE
import android.view.inputmethod.EditorInfo.IME_NULL
import android.widget.ArrayAdapter
import io.github.wulkanowy.BuildConfig.VERSION_NAME
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.login.LoginActivity
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.hideSoftInput
import io.github.wulkanowy.utils.openInternetBrowser
import io.github.wulkanowy.utils.setOnItemSelectedListener
@ -28,6 +28,9 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
@Inject
lateinit var presenter: LoginFormPresenter
@Inject
lateinit var appInfo: AppInfo
companion object {
fun newInstance() = LoginFormFragment()
}
@ -128,7 +131,7 @@ class LoginFormFragment : BaseFragment(), LoginFormView {
override fun showVersion() {
loginFormVersion.apply {
visibility = VISIBLE
text = "${getString(R.string.app_name)} $VERSION_NAME"
text = "${getString(R.string.app_name)} ${appInfo.versionName}"
}
}

View File

@ -3,25 +3,25 @@ package io.github.wulkanowy.ui.modules.login.form
import io.github.wulkanowy.data.repositories.student.StudentRepository
import io.github.wulkanowy.ui.base.BasePresenter
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
import io.github.wulkanowy.utils.SchedulersProvider
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Named
class LoginFormPresenter @Inject constructor(
schedulers: SchedulersProvider,
studentRepository: StudentRepository,
private val loginErrorHandler: LoginErrorHandler,
private val analytics: FirebaseAnalyticsHelper,
@param:Named("isDebug") private val isDebug: Boolean
private val appInfo: AppInfo
) : BasePresenter<LoginFormView>(loginErrorHandler, studentRepository, schedulers) {
override fun onAttachView(view: LoginFormView) {
super.onAttachView(view)
view.run {
initView()
if (isDebug) showVersion() else showPrivacyPolicy()
if (appInfo.isDebug) showVersion() else showPrivacyPolicy()
loginErrorHandler.onBadCredentials = {
setErrorPassIncorrect()

View File

@ -6,5 +6,5 @@ import io.github.wulkanowy.data.db.entities.MobileDevice
class MobileDeviceAdapter<T : IFlexible<*>> : FlexibleAdapter<T>(null, null, true) {
var onDeviceUnregisterListener: (MobileDevice, position: Int) -> Unit = { _, _ -> }
var onDeviceUnregisterListener: (device: MobileDevice, position: Int) -> Unit = { _, _ -> }
}

View File

@ -8,10 +8,10 @@ import android.view.View.VISIBLE
import android.view.ViewGroup
import eu.davidea.flexibleadapter.common.FlexibleItemDecoration
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
import eu.davidea.flexibleadapter.helpers.EmptyViewHelper
import eu.davidea.flexibleadapter.helpers.UndoHelper
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
import io.github.wulkanowy.R
import io.github.wulkanowy.data.db.entities.MobileDevice
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.main.MainActivity
import io.github.wulkanowy.ui.modules.main.MainView
@ -48,7 +48,7 @@ class MobileDeviceFragment : BaseFragment(), MobileDeviceView, MainView.TitledVi
}
override fun initView() {
mobileDevicesRecycler.run {
with(mobileDevicesRecycler) {
layoutManager = SmoothScrollLinearLayoutManager(context)
adapter = devicesAdapter
addItemDecoration(FlexibleItemDecoration(context)
@ -56,37 +56,43 @@ class MobileDeviceFragment : BaseFragment(), MobileDeviceView, MainView.TitledVi
.withDrawDividerOnLastItem(false)
)
}
EmptyViewHelper.create(devicesAdapter, mobileDevicesEmpty)
with(devicesAdapter) {
isPermanentDelete = false
onDeviceUnregisterListener = presenter::onUnregisterDevice
}
mobileDevicesSwipe.setOnRefreshListener { presenter.onSwipeRefresh() }
mobileDeviceAddButton.setOnClickListener { presenter.onRegisterDevice() }
devicesAdapter.run {
isPermanentDelete = false
onDeviceUnregisterListener = { device, position ->
val onActionListener = object : UndoHelper.OnActionListener {
override fun onActionConfirmed(action: Int, event: Int) {
presenter.onUnregister(device)
}
override fun onActionCanceled(action: Int, positions: MutableList<Int>?) {
devicesAdapter.restoreDeletedItems()
}
}
UndoHelper(devicesAdapter, onActionListener)
.withConsecutive(false)
.withAction(UndoHelper.Action.REMOVE)
.start(listOf(position), mobileDevicesRecycler, R.string.mobile_device_removed, R.string.all_undo, 3000)
}
}
}
override fun updateData(data: List<MobileDeviceItem>) {
devicesAdapter.updateDataSet(data)
}
override fun restoreDeleteItem() {
devicesAdapter.restoreDeletedItems()
}
override fun clearData() {
devicesAdapter.clear()
}
override fun showUndo(position: Int, device: MobileDevice) {
val onActionListener = object : UndoHelper.OnActionListener {
override fun onActionConfirmed(action: Int, event: Int) {
presenter.onUnregisterConfirmed(device)
}
override fun onActionCanceled(action: Int, positions: MutableList<Int>?) {
presenter.onUnregisterCancelled()
}
}
UndoHelper(devicesAdapter, onActionListener)
.withConsecutive(false)
.withAction(UndoHelper.Action.REMOVE)
.start(listOf(position), mobileDevicesRecycler, R.string.mobile_device_removed, R.string.all_undo, 3000)
}
override fun hideRefresh() {
mobileDevicesSwipe.isRefreshing = false
}
@ -95,6 +101,10 @@ class MobileDeviceFragment : BaseFragment(), MobileDeviceView, MainView.TitledVi
mobileDevicesProgress.visibility = if (show) VISIBLE else GONE
}
override fun showEmpty(show: Boolean) {
mobileDevicesEmpty.visibility = if (show) VISIBLE else GONE
}
override fun enableSwipe(enable: Boolean) {
mobileDevicesSwipe.isEnabled = enable
}

View File

@ -50,6 +50,7 @@ class MobileDevicePresenter @Inject constructor(
view?.run {
updateData(it)
showContent(it.isNotEmpty())
showEmpty(it.isEmpty())
}
analytics.logEvent("load_devices", "items" to it.size, "force_refresh" to forceRefresh)
}) {
@ -62,13 +63,27 @@ class MobileDevicePresenter @Inject constructor(
view?.showTokenDialog()
}
fun onUnregister(device: MobileDevice) {
fun onUnregisterDevice(device: MobileDevice, position: Int) {
view?.run {
showUndo(position, device)
showEmpty(isViewEmpty)
}
}
fun onUnregisterCancelled() {
view?.run {
restoreDeleteItem()
showEmpty(isViewEmpty)
}
}
fun onUnregisterConfirmed(device: MobileDevice) {
Timber.i("Unregister device started")
disposable.add(studentRepository.getCurrentStudent()
.flatMap { semesterRepository.getCurrentSemester(it) }
.flatMap { semester ->
mobileDeviceRepository.unregisterDevice(semester, device)
.flatMap { mobileDeviceRepository.getDevices(semester, it) }
.flatMap { mobileDeviceRepository.getDevices(semester, it) }
}
.map { items -> items.map { MobileDeviceItem(it) } }
.subscribeOn(schedulers.backgroundThread)
@ -84,6 +99,7 @@ class MobileDevicePresenter @Inject constructor(
view?.run {
updateData(it)
showContent(it.isNotEmpty())
showEmpty(it.isEmpty())
}
}) {
Timber.i("Unregister device result: An exception occurred")

View File

@ -1,5 +1,6 @@
package io.github.wulkanowy.ui.modules.mobiledevice
import io.github.wulkanowy.data.db.entities.MobileDevice
import io.github.wulkanowy.ui.base.BaseView
interface MobileDeviceView : BaseView {
@ -10,6 +11,8 @@ interface MobileDeviceView : BaseView {
fun updateData(data: List<MobileDeviceItem>)
fun restoreDeleteItem()
fun hideRefresh()
fun clearData()
@ -20,5 +23,9 @@ interface MobileDeviceView : BaseView {
fun showContent(show: Boolean)
fun showEmpty(show: Boolean)
fun showUndo(position: Int, device: MobileDevice)
fun showTokenDialog()
}

View File

@ -5,10 +5,10 @@ import android.content.SharedPreferences
import android.os.Bundle
import com.takisoft.preferencex.PreferenceFragmentCompat
import dagger.android.support.AndroidSupportInjection
import io.github.wulkanowy.BuildConfig.DEBUG
import io.github.wulkanowy.R
import io.github.wulkanowy.ui.base.BaseActivity
import io.github.wulkanowy.ui.modules.main.MainView
import io.github.wulkanowy.utils.AppInfo
import javax.inject.Inject
class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPreferenceChangeListener,
@ -17,6 +17,9 @@ class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedP
@Inject
lateinit var presenter: SettingsPresenter
@Inject
lateinit var appInfo: AppInfo
companion object {
fun newInstance() = SettingsFragment()
}
@ -36,7 +39,7 @@ class SettingsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedP
override fun onCreatePreferencesFix(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.scheme_preferences)
findPreference(getString(R.string.pref_key_notification_debug)).isVisible = DEBUG
findPreference(getString(R.string.pref_key_notification_debug)).isVisible = appInfo.isDebug
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {

View File

@ -33,7 +33,7 @@ class SettingsPresenter @Inject constructor(
Timber.i("Change settings $key")
preferencesRepository.apply {
when (key) {
serviceEnableKey -> syncManager.run { if (isServiceEnabled) startSyncWorker() else stopSyncWorker() }
serviceEnableKey -> with(syncManager) { if (isServiceEnabled) startSyncWorker() else stopSyncWorker() }
servicesIntervalKey, servicesOnlyWifiKey -> syncManager.startSyncWorker(true)
isDebugNotificationEnableKey -> chuckCollector.showNotification(isDebugNotificationEnable)
appThemeKey -> view?.recreateView()

View File

@ -0,0 +1,28 @@
package io.github.wulkanowy.utils
import android.os.Build.MANUFACTURER
import android.os.Build.MODEL
import android.os.Build.VERSION.SDK_INT
import io.github.wulkanowy.BuildConfig.CRASHLYTICS_ENABLED
import io.github.wulkanowy.BuildConfig.DEBUG
import io.github.wulkanowy.BuildConfig.VERSION_CODE
import io.github.wulkanowy.BuildConfig.VERSION_NAME
import javax.inject.Singleton
@Singleton
open class AppInfo {
open val isCrashlyticsEnabled get() = CRASHLYTICS_ENABLED
open val isDebug get() = DEBUG
open val versionCode get() = VERSION_CODE
open val versionName get() = VERSION_NAME
open val systemVersion get() = SDK_INT
open val systemManufacturer: String get() = MANUFACTURER
open val systemModel: String get() = MODEL
}

View File

@ -1,14 +1,9 @@
Wersja 0.9.0
Dodaliśmy:
- zarządzanie dostępem mobilnym do dziennika
- wyświetlanie sumy punktów
- wyświetlanie informacji o wygasłej sesji, gdy zostanie zmienione hasło
Wersja 0.9.2
Naprawiliśmy:
- wykrywanie uczniów przy logowaniu, jeśli symbol zawiera cyfry
- błędne wyświetlanie średniej
- synchronizację w tle na danych komórkowych przy domyślnych ustawieniach
- rzadkie błędy podczas ładowania szczęśliwego numerka
- ustawienia synchronizacji w tle
- ręczne odświeżanie ocen jeśli średnia była pobierana z dziennika
- wygląd ładowania w widoku Dostęp Mobilny
- sporadyczne awarie aplikacji na starszych urządzeniach
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases

View File

@ -20,7 +20,7 @@
android:gravity="center"
android:orientation="vertical"
android:padding="10dp"
android:alpha="0.0">
android:visibility="gone">
<TextView
android:layout_width="wrap_content"

View File

@ -7,7 +7,7 @@
<item>2 godziny</item>
<item>6 godzin</item>
<item>12 godzin</item>
<item>24 godzin</item>
<item>24 godziny</item>
</string-array>
<string-array name="app_theme_entries">

View File

@ -4,9 +4,21 @@ import android.content.Context
import com.crashlytics.android.Crashlytics
import com.crashlytics.android.core.CrashlyticsCore
import io.fabric.sdk.android.Fabric
import io.github.wulkanowy.BuildConfig
import timber.log.Timber
fun initCrashlytics(context: Context, appInfo: AppInfo) {
Fabric.with(Fabric.Builder(context)
.kits(
Crashlytics.Builder()
.core(CrashlyticsCore.Builder()
.disabled(!appInfo.isCrashlyticsEnabled)
.build())
.build()
)
.debuggable(appInfo.isDebug)
.build())
}
class CrashlyticsTree : Timber.Tree() {
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
@ -17,9 +29,3 @@ class CrashlyticsTree : Timber.Tree() {
else Crashlytics.logException(t)
}
}
fun initCrashlytics(context: Context) {
Fabric.with(Fabric.Builder(context).kits(
Crashlytics.Builder().core(CrashlyticsCore.Builder().disabled(!BuildConfig.CRASHLYTICS_ENABLED).build()).build()
).debuggable(BuildConfig.DEBUG).build())
}

View File

@ -4,6 +4,7 @@ import io.github.wulkanowy.TestSchedulersProvider
import io.github.wulkanowy.data.db.entities.Student
import io.github.wulkanowy.data.repositories.student.StudentRepository
import io.github.wulkanowy.ui.modules.login.LoginErrorHandler
import io.github.wulkanowy.utils.AppInfo
import io.github.wulkanowy.utils.FirebaseAnalyticsHelper
import io.reactivex.Single
import org.junit.Before
@ -33,13 +34,16 @@ class LoginFormPresenterTest {
@Mock
lateinit var analytics: FirebaseAnalyticsHelper
@Mock
lateinit var appInfo: AppInfo
private lateinit var presenter: LoginFormPresenter
@Before
fun initPresenter() {
MockitoAnnotations.initMocks(this)
clearInvocations(repository, loginFormView)
presenter = LoginFormPresenter(TestSchedulersProvider(), repository, errorHandler, analytics, false)
presenter = LoginFormPresenter(TestSchedulersProvider(), repository, errorHandler, analytics, appInfo)
presenter.onAttachView(loginFormView)
}