forked from github/szkolny
Compare commits
34 Commits
v3.9.6-dev
...
v3.9.10-de
Author | SHA1 | Date | |
---|---|---|---|
19bc2b8b37 | |||
673116e27e | |||
59fcb0a050 | |||
cd76f99bbf | |||
6a4994b9c2 | |||
63960c5e05 | |||
540afb6a28 | |||
ae10b8abbd | |||
db2ebab879 | |||
6ec3d062df | |||
86b6060a09 | |||
83d123e341 | |||
34061695f9 | |||
de68476442 | |||
678a81a44b | |||
cfb3096d53 | |||
9b7aca745a | |||
82852389fa | |||
ce06084e6f | |||
3ca051983f | |||
cd379e4175 | |||
62fdfa2b6f | |||
9866017f7e | |||
67f98b08c6 | |||
fdb5f7ec02 | |||
04c3c7ca6e | |||
f424315d97 | |||
c907a8df37 | |||
37ea65e3fc | |||
a3e5f824c8 | |||
e0c850a455 | |||
1c6815f708 | |||
9a20511935 | |||
965f5e73d9 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -81,3 +81,5 @@ lint/generated/
|
||||
lint/outputs/
|
||||
lint/tmp/
|
||||
# lint/reports/
|
||||
|
||||
app/schemas/
|
||||
|
@ -169,7 +169,7 @@ dependencies {
|
||||
|
||||
implementation 'com.github.kuba2k2:RecyclerTabLayout:700f980584'
|
||||
|
||||
implementation 'com.linkedin.android.tachyon:tachyon:1.0.2'
|
||||
implementation 'com.github.kuba2k2:Tachyon:551943a6b5'
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
@ -4,7 +4,9 @@ import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Typeface
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.*
|
||||
@ -13,9 +15,11 @@ import android.text.style.StrikethroughSpan
|
||||
import android.text.style.StyleSpan
|
||||
import android.util.LongSparseArray
|
||||
import android.util.SparseArray
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import android.widget.CompoundButton
|
||||
import android.widget.TextView
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.annotation.*
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.util.forEach
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
@ -438,6 +442,13 @@ inline fun <T : View> T.onClick(crossinline onClickListener: (v: T) -> Unit) {
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline fun <T : CompoundButton> T.onChange(crossinline onChangeListener: (v: T, isChecked: Boolean) -> Unit) {
|
||||
setOnCheckedChangeListener { buttonView, isChecked ->
|
||||
onChangeListener(buttonView as T, isChecked)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> LiveData<T>.observeOnce(lifecycleOwner: LifecycleOwner, observer: Observer<T>) {
|
||||
observe(lifecycleOwner, object : Observer<T> {
|
||||
override fun onChanged(t: T?) {
|
||||
@ -446,3 +457,49 @@ fun <T> LiveData<T>.observeOnce(lifecycleOwner: LifecycleOwner, observer: Observ
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a value in dp to pixels.
|
||||
*/
|
||||
val Int.dp: Int
|
||||
get() = (this * Resources.getSystem().displayMetrics.density).toInt()
|
||||
/**
|
||||
* Convert a value in pixels to dp.
|
||||
*/
|
||||
val Int.px: Int
|
||||
get() = (this / Resources.getSystem().displayMetrics.density).toInt()
|
||||
|
||||
@ColorInt
|
||||
fun @receiver:AttrRes Int.resolveAttr(context: Context?): Int {
|
||||
val typedValue = TypedValue()
|
||||
context?.theme?.resolveAttribute(this, typedValue, true)
|
||||
return typedValue.data
|
||||
}
|
||||
@ColorInt
|
||||
fun @receiver:ColorRes Int.resolveColor(context: Context): Int {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
context.resources.getColor(this, context.theme)
|
||||
}
|
||||
else {
|
||||
context.resources.getColor(this)
|
||||
}
|
||||
}
|
||||
fun @receiver:DrawableRes Int.resolveDrawable(context: Context): Drawable {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
context.resources.getDrawable(this, context.theme)
|
||||
}
|
||||
else {
|
||||
context.resources.getDrawable(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun View.findParentById(targetId: Int): View? {
|
||||
if (id == targetId) {
|
||||
return this
|
||||
}
|
||||
val viewParent = this.parent ?: return null
|
||||
if (viewParent is View) {
|
||||
return viewParent.findParentById(targetId)
|
||||
}
|
||||
return null
|
||||
}
|
@ -124,7 +124,7 @@ class MainActivity : AppCompatActivity() {
|
||||
// home item
|
||||
list += NavTarget(DRAWER_ITEM_HOME, R.string.menu_home_page, HomeFragment::class)
|
||||
.withTitle(R.string.app_name)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_home)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_home_outline)
|
||||
.isInDrawer(true)
|
||||
.isStatic(true)
|
||||
.withPopToHome(false)
|
||||
@ -135,50 +135,50 @@ class MainActivity : AppCompatActivity() {
|
||||
.isInDrawer(true)
|
||||
|
||||
list += NavTarget(DRAWER_ITEM_AGENDA, R.string.menu_agenda, AgendaFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_calendar)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_calendar_outline)
|
||||
.withBadgeTypeId(TYPE_EVENT)
|
||||
.isInDrawer(true)
|
||||
|
||||
list += NavTarget(DRAWER_ITEM_GRADES, R.string.menu_grades, GradesFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_numeric_5_box)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_numeric_5_box_outline)
|
||||
.withBadgeTypeId(TYPE_GRADE)
|
||||
.isInDrawer(true)
|
||||
|
||||
list += NavTarget(DRAWER_ITEM_MESSAGES, R.string.menu_messages, MessagesFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_email)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_email_outline)
|
||||
.withBadgeTypeId(TYPE_MESSAGE)
|
||||
.isInDrawer(true)
|
||||
|
||||
list += NavTarget(DRAWER_ITEM_HOMEWORK, R.string.menu_homework, HomeworkFragment::class)
|
||||
.withIcon(SzkolnyFont.Icon.szf_file_document_edit)
|
||||
.withIcon(SzkolnyFont.Icon.szf_notebook_outline)
|
||||
.withBadgeTypeId(TYPE_HOMEWORK)
|
||||
.isInDrawer(true)
|
||||
|
||||
list += NavTarget(DRAWER_ITEM_BEHAVIOUR, R.string.menu_notices, BehaviourFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_message_alert)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_emoticon_outline)
|
||||
.withBadgeTypeId(TYPE_NOTICE)
|
||||
.isInDrawer(true)
|
||||
|
||||
list += NavTarget(DRAWER_ITEM_ATTENDANCE, R.string.menu_attendance, AttendanceFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_calendar_remove)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_calendar_remove_outline)
|
||||
.withBadgeTypeId(TYPE_ATTENDANCE)
|
||||
.isInDrawer(true)
|
||||
|
||||
list += NavTarget(DRAWER_ITEM_ANNOUNCEMENTS, R.string.menu_announcements, AnnouncementsFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_bulletin_board)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_bullhorn_outline)
|
||||
.withBadgeTypeId(TYPE_ANNOUNCEMENT)
|
||||
.isInDrawer(true)
|
||||
|
||||
|
||||
// static drawer items
|
||||
list += NavTarget(DRAWER_ITEM_NOTIFICATIONS, R.string.menu_notifications, NotificationsFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_bell_ring)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_bell_ring_outline)
|
||||
.isInDrawer(true)
|
||||
.isStatic(true)
|
||||
.isBelowSeparator(true)
|
||||
|
||||
list += NavTarget(DRAWER_ITEM_SETTINGS, R.string.menu_settings, SettingsNewFragment::class)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_settings)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_settings_outline)
|
||||
.isInDrawer(true)
|
||||
.isStatic(true)
|
||||
.isBelowSeparator(true)
|
||||
@ -197,7 +197,7 @@ class MainActivity : AppCompatActivity() {
|
||||
.isInProfileList(false)
|
||||
|
||||
list += NavTarget(DRAWER_PROFILE_SYNC_ALL, R.string.menu_sync_all, null)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_sync)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_download_outline)
|
||||
.isInProfileList(true)
|
||||
|
||||
|
||||
@ -376,6 +376,11 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
b.swipeRefreshLayout.isEnabled = true
|
||||
b.swipeRefreshLayout.setOnRefreshListener { this.syncCurrentFeature() }
|
||||
b.swipeRefreshLayout.setColorSchemeResources(
|
||||
R.color.md_blue_500,
|
||||
R.color.md_amber_500,
|
||||
R.color.md_green_500
|
||||
)
|
||||
|
||||
isStoragePermissionGranted()
|
||||
|
||||
@ -429,7 +434,7 @@ class MainActivity : AppCompatActivity() {
|
||||
navView.coordinator.postDelayed({
|
||||
CafeBar.builder(this)
|
||||
.content(R.string.rate_snackbar_text)
|
||||
.icon(IconicsDrawable(this).icon(CommunityMaterial.Icon2.cmd_star).size(IconicsSize.dp(20)).color(IconicsColor.colorInt(Themes.getPrimaryTextColor(this))))
|
||||
.icon(IconicsDrawable(this).icon(CommunityMaterial.Icon2.cmd_star_outline).size(IconicsSize.dp(20)).color(IconicsColor.colorInt(Themes.getPrimaryTextColor(this))))
|
||||
.positiveText(R.string.rate_snackbar_positive)
|
||||
.positiveColor(-0xb350b0)
|
||||
.negativeText(R.string.rate_snackbar_negative)
|
||||
@ -466,7 +471,7 @@ class MainActivity : AppCompatActivity() {
|
||||
bottomSheet.appendItems(
|
||||
BottomSheetPrimaryItem(false)
|
||||
.withTitle(R.string.menu_sync)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_sync)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_download_outline)
|
||||
.withOnClickListener(View.OnClickListener {
|
||||
bottomSheet.close()
|
||||
SyncViewListDialog(this, navTargetId)
|
||||
@ -474,17 +479,17 @@ class MainActivity : AppCompatActivity() {
|
||||
BottomSheetSeparatorItem(false),
|
||||
BottomSheetPrimaryItem(false)
|
||||
.withTitle(R.string.menu_settings)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_settings)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_settings_outline)
|
||||
.withOnClickListener(View.OnClickListener { loadTarget(DRAWER_ITEM_SETTINGS) }),
|
||||
BottomSheetPrimaryItem(false)
|
||||
.withTitle(R.string.menu_feedback)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_help_circle)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_help_circle_outline)
|
||||
.withOnClickListener(View.OnClickListener { loadTarget(TARGET_FEEDBACK) })
|
||||
)
|
||||
if (App.devMode) {
|
||||
bottomSheet += BottomSheetPrimaryItem(false)
|
||||
.withTitle(R.string.menu_debug)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_android_debug_bridge)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_android_studio)
|
||||
.withOnClickListener(View.OnClickListener { loadTarget(DRAWER_ITEM_DEBUG) })
|
||||
}
|
||||
|
||||
@ -532,9 +537,16 @@ class MainActivity : AppCompatActivity() {
|
||||
DRAWER_ITEM_MESSAGES -> MessagesFragment.pageSelection
|
||||
else -> 0
|
||||
}
|
||||
val arguments = when (navTargetId) {
|
||||
DRAWER_ITEM_TIMETABLE -> JsonObject().apply {
|
||||
addProperty("weekStart", TimetableFragment.pageSelection?.weekStart?.stringY_m_d)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
EdziennikTask.syncProfile(
|
||||
App.profileId,
|
||||
listOf(navTargetId to fragmentParam)
|
||||
listOf(navTargetId to fragmentParam),
|
||||
arguments
|
||||
).enqueue(this)
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
@ -689,10 +701,10 @@ class MainActivity : AppCompatActivity() {
|
||||
app.profile == null -> {
|
||||
if (intentProfileId == -1)
|
||||
intentProfileId = app.appSharedPrefs.getInt("current_profile_id", 1)
|
||||
loadProfile(intentProfileId, intentTargetId)
|
||||
loadProfile(intentProfileId, intentTargetId, extras)
|
||||
}
|
||||
intentProfileId != -1 -> {
|
||||
loadProfile(intentProfileId, intentTargetId)
|
||||
loadProfile(intentProfileId, intentTargetId, extras)
|
||||
}
|
||||
intentTargetId != -1 -> {
|
||||
drawer.currentProfile = app.profile.id
|
||||
|
@ -311,13 +311,14 @@ public class Notifier {
|
||||
\____/| .__/ \__,_|\__,_|\__\___||___/
|
||||
| |
|
||||
|*/
|
||||
public void notificationUpdatesShow(String updateVersion, String updateUrl, String updateFilename) {
|
||||
public void notificationUpdatesShow(String updateVersion, String updateUrl, String updateFilename, boolean updateDirect) {
|
||||
if (!app.appConfig.notifyAboutUpdates)
|
||||
return;
|
||||
Intent notificationIntent = new Intent(app.getContext(), BootReceiver.NotificationActionService.class)
|
||||
.putExtra("update_version", updateVersion)
|
||||
.putExtra("update_url", updateUrl)
|
||||
.putExtra("update_filename", updateFilename);
|
||||
.putExtra("update_filename", updateFilename)
|
||||
.putExtra("update_direct", updateDirect);
|
||||
|
||||
PendingIntent pendingIntent = PendingIntent.getService(app.getContext(), 0,
|
||||
notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
|
@ -87,7 +87,7 @@ class WidgetTimetable : AppWidgetProvider() {
|
||||
.colorInt(Color.WHITE)
|
||||
.sizeDp(if (widgetConfig.bigStyle) 24 else 16).toBitmap())
|
||||
|
||||
views.setImageViewBitmap(R.id.widgetTimetableSync, IconicsDrawable(context, CommunityMaterial.Icon2.cmd_sync)
|
||||
views.setImageViewBitmap(R.id.widgetTimetableSync, IconicsDrawable(context, CommunityMaterial.Icon.cmd_download_outline)
|
||||
.colorInt(Color.WHITE)
|
||||
.sizeDp(if (widgetConfig.bigStyle) 24 else 16).toBitmap())
|
||||
|
||||
@ -185,12 +185,12 @@ class WidgetTimetable : AppWidgetProvider() {
|
||||
// search for lessons to display
|
||||
val timetableDate = Date.getToday()
|
||||
var checkedDays = 0
|
||||
var lessons = lessonList.filter { it.profileId == profile.id && it.displayDate == timetableDate }
|
||||
var lessons = lessonList.filter { it.profileId == profile.id && it.displayDate == timetableDate && it.type != Lesson.TYPE_NO_LESSONS }
|
||||
while ((lessons.isEmpty() || lessons.none {
|
||||
it.displayDate != today || (it.displayDate == today && it.displayEndTime != null && it.displayEndTime!! >= now)
|
||||
}) && checkedDays < 7) {
|
||||
timetableDate.stepForward(0, 0, 1)
|
||||
lessons = lessonList.filter { it.profileId == profile.id && it.displayDate == timetableDate }
|
||||
lessons = lessonList.filter { it.profileId == profile.id && it.displayDate == timetableDate && it.type != Lesson.TYPE_NO_LESSONS }
|
||||
checkedDays++
|
||||
}
|
||||
|
||||
@ -214,8 +214,8 @@ class WidgetTimetable : AppWidgetProvider() {
|
||||
|
||||
model.lessonId = lesson.id
|
||||
model.lessonDate = timetableDate
|
||||
model.startTime = lesson.startTime
|
||||
model.endTime = lesson.endTime
|
||||
model.startTime = lesson.displayStartTime
|
||||
model.endTime = lesson.displayEndTime
|
||||
|
||||
// check if the lesson has already passed or it's currently in progress
|
||||
if (lesson.displayDate == today) {
|
||||
|
@ -60,6 +60,9 @@ class ApiService : Service() {
|
||||
|
||||
private val notification by lazy { EdziennikNotification(this) }
|
||||
|
||||
private var lastEventTime = System.currentTimeMillis()
|
||||
private var taskCancelTries = 0
|
||||
|
||||
/* ______ _ _ _ _ _____ _ _ _ _
|
||||
| ____| | | (_) (_) | / ____| | | | | | |
|
||||
| |__ __| |_____ ___ _ __ _ __ _| | __ | | __ _| | | |__ __ _ ___| | __
|
||||
@ -68,22 +71,17 @@ class ApiService : Service() {
|
||||
|______\__,_/___|_|\___|_| |_|_| |_|_|_|\_\ \_____\__,_|_|_|_.__/ \__,_|\___|_|\*/
|
||||
private val taskCallback = object : EdziennikCallback {
|
||||
override fun onCompleted() {
|
||||
lastEventTime = System.currentTimeMillis()
|
||||
d(TAG, "Task $taskRunningId (profile $taskProfileId) - $taskProgressText - finished")
|
||||
//if (!taskCancelled) {
|
||||
EventBus.getDefault().post(ApiTaskFinishedEvent(taskProfileId))
|
||||
//}
|
||||
taskIsRunning = false
|
||||
taskRunningId = -1
|
||||
taskRunning = null
|
||||
taskProfileId = -1
|
||||
taskProgress = -1f
|
||||
taskProgressText = null
|
||||
EventBus.getDefault().post(ApiTaskFinishedEvent(taskProfileId))
|
||||
clearTask()
|
||||
|
||||
notification.setIdle().post()
|
||||
runTask()
|
||||
}
|
||||
|
||||
override fun onError(apiError: ApiError) {
|
||||
lastEventTime = System.currentTimeMillis()
|
||||
d(TAG, "Task $taskRunningId threw an error - $apiError")
|
||||
apiError.profileId = taskProfileId
|
||||
EventBus.getDefault().post(ApiTaskErrorEvent(apiError))
|
||||
@ -92,9 +90,7 @@ class ApiService : Service() {
|
||||
if (apiError.isCritical) {
|
||||
taskRunning?.cancel()
|
||||
notification.setCriticalError().post()
|
||||
taskRunning = null
|
||||
taskIsRunning = false
|
||||
taskRunningId = -1
|
||||
clearTask()
|
||||
runTask()
|
||||
}
|
||||
else {
|
||||
@ -103,6 +99,7 @@ class ApiService : Service() {
|
||||
}
|
||||
|
||||
override fun onProgress(step: Float) {
|
||||
lastEventTime = System.currentTimeMillis()
|
||||
if (step <= 0)
|
||||
return
|
||||
if (taskProgress < 0)
|
||||
@ -115,6 +112,7 @@ class ApiService : Service() {
|
||||
}
|
||||
|
||||
override fun onStartProgress(stringRes: Int) {
|
||||
lastEventTime = System.currentTimeMillis()
|
||||
taskProgressText = getString(stringRes)
|
||||
d(TAG, "Task $taskRunningId progress: $taskProgressText")
|
||||
EventBus.getDefault().post(ApiTaskProgressEvent(taskProfileId, taskProgress, taskProgressText))
|
||||
@ -129,6 +127,7 @@ class ApiService : Service() {
|
||||
| | (_| \__ \ < | __/> < __/ (__| |_| | |_| | (_) | | | |
|
||||
|_|\__,_|___/_|\_\ \___/_/\_\___|\___|\__,_|\__|_|\___/|_| |*/
|
||||
private fun runTask() {
|
||||
checkIfTaskFrozen()
|
||||
if (taskIsRunning)
|
||||
return
|
||||
if (taskCancelled || serviceClosed || (taskQueue.isEmpty() && finishingTaskQueue.isEmpty())) {
|
||||
@ -137,6 +136,8 @@ class ApiService : Service() {
|
||||
return
|
||||
}
|
||||
|
||||
lastEventTime = System.currentTimeMillis()
|
||||
|
||||
val task = if (taskQueue.isEmpty()) finishingTaskQueue.removeAt(0) else taskQueue.removeAt(0)
|
||||
task.taskId = ++taskMaximumId
|
||||
task.prepare(app)
|
||||
@ -166,6 +167,48 @@ class ApiService : Service() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a task is inactive for more than 30 seconds.
|
||||
* If the user tries to cancel a task with no success at least three times,
|
||||
* consider it frozen as well.
|
||||
*
|
||||
* This usually means it is broken and won't become active again.
|
||||
* This method cancels the task and removes any pointers to it.
|
||||
*/
|
||||
private fun checkIfTaskFrozen(): Boolean {
|
||||
if (System.currentTimeMillis() - lastEventTime > 30*1000
|
||||
|| taskCancelTries >= 3) {
|
||||
val time = System.currentTimeMillis() - lastEventTime
|
||||
d(TAG, "!!! Task $taskRunningId froze for $time ms. $taskRunning")
|
||||
clearTask()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the service if the current task is frozen/broken.
|
||||
*/
|
||||
private fun stopIfTaskFrozen() {
|
||||
if (checkIfTaskFrozen()) {
|
||||
stopSelf()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any task descriptors or pointers from the service.
|
||||
*/
|
||||
private fun clearTask() {
|
||||
taskIsRunning = false
|
||||
taskRunningId = -1
|
||||
taskRunning = null
|
||||
taskProfileId = -1
|
||||
taskProgress = -1f
|
||||
taskProgressText = null
|
||||
taskCancelled = false
|
||||
taskCancelTries = 0
|
||||
}
|
||||
|
||||
private fun allCompleted() {
|
||||
EventBus.getDefault().post(ApiTaskAllFinishedEvent())
|
||||
stopSelf()
|
||||
@ -211,8 +254,10 @@ class ApiService : Service() {
|
||||
EventBus.getDefault().removeStickyEvent(request)
|
||||
d(TAG, request.toString())
|
||||
|
||||
taskCancelTries++
|
||||
taskCancelled = true
|
||||
taskRunning?.cancel()
|
||||
stopIfTaskFrozen()
|
||||
}
|
||||
@Subscribe(sticky = true, threadMode = ThreadMode.ASYNC)
|
||||
fun onServiceCloseRequest(request: ServiceCloseRequest) {
|
||||
|
@ -39,9 +39,11 @@ const val ERROR_REQUEST_HTTP_404 = 54
|
||||
const val ERROR_REQUEST_HTTP_405 = 55
|
||||
const val ERROR_REQUEST_HTTP_410 = 56
|
||||
const val ERROR_REQUEST_HTTP_500 = 57
|
||||
const val ERROR_REQUEST_FAILURE_HOSTNAME_NOT_FOUND = 60
|
||||
const val ERROR_REQUEST_FAILURE_TIMEOUT = 61
|
||||
const val ERROR_REQUEST_FAILURE_NO_INTERNET = 62
|
||||
const val ERROR_RESPONSE_EMPTY = 100
|
||||
const val ERROR_LOGIN_DATA_MISSING = 101
|
||||
const val ERROR_LOGIN_DATA_INVALID = 102
|
||||
const val ERROR_PROFILE_MISSING = 105
|
||||
const val ERROR_INVALID_LOGIN_MODE = 110
|
||||
const val ERROR_LOGIN_METHOD_NOT_SATISFIED = 111
|
||||
@ -99,6 +101,13 @@ const val ERROR_LOGIN_LIBRUS_PORTAL_REFRESH_INVALID = 172
|
||||
const val ERROR_LOGIN_LIBRUS_PORTAL_REFRESH_REVOKED = 173
|
||||
const val ERROR_LIBRUS_SYNERGIA_OTHER = 174
|
||||
const val ERROR_LIBRUS_SYNERGIA_MAINTENANCE = 175
|
||||
const val ERROR_LIBRUS_MESSAGES_MAINTENANCE = 176
|
||||
const val ERROR_LIBRUS_MESSAGES_ERROR = 177
|
||||
const val ERROR_LIBRUS_MESSAGES_OTHER = 178
|
||||
const val ERROR_LOGIN_LIBRUS_MESSAGES_INVALID_LOGIN = 179
|
||||
const val ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN = 180
|
||||
const val ERROR_LIBRUS_API_MAINTENANCE = 181
|
||||
const val ERROR_LIBRUS_PORTAL_MAINTENANCE = 182
|
||||
|
||||
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_LOGIN = 201
|
||||
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_OLD_PASSWORD = 202
|
||||
|
@ -37,6 +37,16 @@ object Regexes {
|
||||
"""events: (.+),$""".toRegex(RegexOption.MULTILINE)
|
||||
}
|
||||
|
||||
val MOBIDZIENNIK_MESSAGE_READ_DATE by lazy {
|
||||
"""czas przeczytania:.+?,\s([0-9]+)\s(.+?)\s([0-9]{4}),\sgodzina\s([0-9:]+)""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_MESSAGE_SENT_READ_DATE by lazy {
|
||||
""".+?,\s([0-9]+)\s(.+?)\s([0-9]{4}),\sgodzina\s([0-9:]+)""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_MESSAGE_ATTACHMENT by lazy {
|
||||
"""href="https://.+?\.mobidziennik.pl/.+?&(?:amp;)?zalacznik=([0-9]+)"(?:.+?<small.+?\(([0-9.]+)\s(M|K|G|)B\))*""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
}
|
||||
|
||||
|
||||
|
||||
val IDZIENNIK_LOGIN_HIDDEN_FIELDS by lazy {
|
||||
@ -61,6 +71,8 @@ object Regexes {
|
||||
"""<option.*?value="([0-9]+)"\sdata-id-ucznia="([A-z0-9]+?)".*?>(.+?)\s(.+?)\s*\((.+?),\s*(.+?)\)</option>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
}
|
||||
|
||||
|
||||
|
||||
val VULCAN_SHITFT_ANNOTATION by lazy {
|
||||
"""\(przeniesiona (z|na) lekcj[ię] ([0-9]+), (.+)\)""".toRegex()
|
||||
}
|
||||
|
@ -138,10 +138,12 @@ class DataIdziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data(
|
||||
val teacher = teacherList.singleOrNull { it.fullName == "$firstName $lastName" }
|
||||
return validateTeacher(teacher, firstName, lastName)
|
||||
}
|
||||
|
||||
fun getTeacher(firstNameChar: Char, lastName: String): Teacher {
|
||||
val teacher = teacherList.singleOrNull { it.shortName == "$firstNameChar.$lastName" }
|
||||
return validateTeacher(teacher, firstNameChar.toString(), lastName)
|
||||
}
|
||||
|
||||
fun getTeacherByLastFirst(nameLastFirst: String): Teacher {
|
||||
val nameParts = nameLastFirst.split(" ")
|
||||
return if (nameParts.size == 1) getTeacher(nameParts[0], "") else getTeacher(nameParts[1], nameParts[0])
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-27.
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-11-22
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
|
||||
@ -12,33 +12,38 @@ import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_TIMETABLE
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.Lesson
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange.TYPE_CANCELLED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange.TYPE_CHANGE
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonRange
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||
|
||||
class IdziennikWebTimetable(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebTimetable"
|
||||
}
|
||||
|
||||
init {
|
||||
val weekStart = Week.getWeekStart()
|
||||
val currentWeekStart = Week.getWeekStart()
|
||||
|
||||
if (Date.getToday().weekDay > 4) {
|
||||
weekStart.stepForward(0, 0, 7)
|
||||
currentWeekStart.stepForward(0, 0, 7)
|
||||
}
|
||||
|
||||
val getDate = data.arguments?.getString("weekStart") ?: currentWeekStart.stringY_m_d
|
||||
|
||||
val weekStart = Date.fromY_m_d(getDate)
|
||||
val weekEnd = weekStart.clone().stepForward(0, 0, 6)
|
||||
|
||||
webApiGet(TAG, IDZIENNIK_WEB_TIMETABLE, mapOf(
|
||||
"idPozDziennika" to data.registerId,
|
||||
"pidRokSzkolny" to data.schoolYearId,
|
||||
"data" to weekStart.stringY_m_d+"T10:00:00.000Z"
|
||||
"data" to "${weekStart.stringY_m_d}T10:00:00.000Z"
|
||||
)) { result ->
|
||||
val json = result.getJsonObject("d") ?: run {
|
||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
||||
@ -56,64 +61,103 @@ class IdziennikWebTimetable(override val data: DataIdziennik,
|
||||
data.lessonRanges[lessonRange.lessonNumber] = lessonRange
|
||||
}
|
||||
|
||||
val dates = mutableSetOf<Int>()
|
||||
val lessons = mutableListOf<Lesson>()
|
||||
|
||||
json.getJsonArray("Przedmioty")?.asJsonObjectList()?.forEach { lesson ->
|
||||
val subject = data.getSubject(
|
||||
lesson.getString("Nazwa") ?: return@forEach,
|
||||
lesson.getLong("Id"),
|
||||
lesson.getString("Skrot") ?: ""
|
||||
)
|
||||
val teacher = data.getTeacherByFDotLast(lesson.getString("Nauczyciel") ?: return@forEach)
|
||||
val weekDay = lesson.getInt("DzienTygodnia")?.minus(1) ?: return@forEach
|
||||
val lessonRange = data.lessonRanges[lesson.getInt("Godzina")?.plus(1) ?: return@forEach]
|
||||
val teacher = data.getTeacherByFDotLast(lesson.getString("Nauczyciel")
|
||||
?: return@forEach)
|
||||
|
||||
val lessonObject = Lesson(
|
||||
profileId,
|
||||
weekDay,
|
||||
lessonRange.startTime,
|
||||
lessonRange.endTime
|
||||
).apply {
|
||||
subjectId = subject.id
|
||||
teacherId = teacher.id
|
||||
teamId = data.teamClass?.id ?: -1
|
||||
classroomName = lesson.getString("NazwaSali") ?: ""
|
||||
val newSubjectName = lesson.getString("PrzedmiotZastepujacy")
|
||||
val newSubject = when (newSubjectName.isNullOrBlank()) {
|
||||
true -> null
|
||||
else -> data.getSubject(newSubjectName, null, newSubjectName)
|
||||
}
|
||||
|
||||
data.lessonList.add(lessonObject)
|
||||
val newTeacherName = lesson.getString("NauZastepujacy")
|
||||
val newTeacher = when (newTeacherName.isNullOrBlank()) {
|
||||
true -> null
|
||||
else -> data.getTeacherByFDotLast(newTeacherName)
|
||||
}
|
||||
|
||||
val weekDay = lesson.getInt("DzienTygodnia")?.minus(1) ?: return@forEach
|
||||
val lessonRange = data.lessonRanges[lesson.getInt("Godzina")?.plus(1)
|
||||
?: return@forEach]
|
||||
val lessonDate = weekStart.clone().stepForward(0, 0, weekDay)
|
||||
val classroom = lesson.getString("NazwaSali")
|
||||
|
||||
val id = lessonDate.combineWith(lessonRange.startTime) / 6L * 10L + (lesson.hashCode() and 0xFFFF)
|
||||
val type = lesson.getInt("TypZastepstwa") ?: -1
|
||||
if (type != -1) {
|
||||
// we have a lesson change to process
|
||||
val lessonChangeObject = LessonChange(
|
||||
profileId,
|
||||
weekStart.clone().stepForward(0, 0, weekDay),
|
||||
lessonObject.startTime,
|
||||
lessonObject.endTime
|
||||
)
|
||||
|
||||
lessonChangeObject.teamId = lessonObject.teamId
|
||||
lessonChangeObject.teacherId = lessonObject.teacherId
|
||||
lessonChangeObject.subjectId = lessonObject.subjectId
|
||||
lessonChangeObject.classroomName = lessonObject.classroomName
|
||||
when (type) {
|
||||
0 -> lessonChangeObject.type = TYPE_CANCELLED
|
||||
1, 2, 3, 4, 5 -> {
|
||||
lessonChangeObject.type = TYPE_CHANGE
|
||||
val newTeacher = lesson.getString("NauZastepujacy")
|
||||
val newSubject = lesson.getString("PrzedmiotZastepujacy")
|
||||
if (newTeacher != null) {
|
||||
lessonChangeObject.teacherId = data.getTeacherByFDotLast(newTeacher).id
|
||||
}
|
||||
if (newSubject != null) {
|
||||
lessonChangeObject.subjectId = data.getSubject(newSubject, null, "").id
|
||||
}
|
||||
val lessonObject = Lesson(profileId, id)
|
||||
|
||||
when (type) {
|
||||
1, 2, 3, 4, 5 -> {
|
||||
lessonObject.apply {
|
||||
this.type = Lesson.TYPE_CHANGE
|
||||
|
||||
this.date = lessonDate
|
||||
this.lessonNumber = lessonRange.lessonNumber
|
||||
this.startTime = lessonRange.startTime
|
||||
this.endTime = lessonRange.endTime
|
||||
this.subjectId = newSubject?.id
|
||||
this.teacherId = newTeacher?.id
|
||||
this.teamId = data.teamClass?.id
|
||||
this.classroom = classroom
|
||||
|
||||
this.oldDate = lessonDate
|
||||
this.oldLessonNumber = lessonRange.lessonNumber
|
||||
this.oldStartTime = lessonRange.startTime
|
||||
this.oldEndTime = lessonRange.endTime
|
||||
this.oldSubjectId = subject.id
|
||||
this.oldTeacherId = teacher.id
|
||||
this.oldTeamId = data.teamClass?.id
|
||||
this.oldClassroom = classroom
|
||||
}
|
||||
}
|
||||
0 -> {
|
||||
lessonObject.apply {
|
||||
this.type = Lesson.TYPE_CANCELLED
|
||||
|
||||
data.lessonChangeList.add(lessonChangeObject)
|
||||
this.oldDate = lessonDate
|
||||
this.oldLessonNumber = lessonRange.lessonNumber
|
||||
this.oldStartTime = lessonRange.startTime
|
||||
this.oldEndTime = lessonRange.endTime
|
||||
this.oldSubjectId = subject.id
|
||||
this.oldTeacherId = teacher.id
|
||||
this.oldTeamId = data.teamClass?.id
|
||||
this.oldClassroom = classroom
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
lessonObject.apply {
|
||||
this.type = Lesson.TYPE_NORMAL
|
||||
|
||||
this.date = lessonDate
|
||||
this.lessonNumber = lessonRange.lessonNumber
|
||||
this.startTime = lessonRange.startTime
|
||||
this.endTime = lessonRange.endTime
|
||||
this.subjectId = subject.id
|
||||
this.teacherId = teacher.id
|
||||
this.teamId = data.teamClass?.id
|
||||
this.classroom = classroom
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dates.add(lessonDate.value)
|
||||
lessons.add(lessonObject)
|
||||
|
||||
if (lessonObject.type != Lesson.TYPE_NORMAL && lessonDate >= Date.getToday()) {
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_LESSON_CHANGE,
|
||||
lessonChangeObject.id,
|
||||
lessonObject.id,
|
||||
profile?.empty ?: false,
|
||||
profile?.empty ?: false,
|
||||
System.currentTimeMillis()
|
||||
@ -121,6 +165,23 @@ class IdziennikWebTimetable(override val data: DataIdziennik,
|
||||
}
|
||||
}
|
||||
|
||||
val date: Date = weekStart.clone()
|
||||
while (date <= weekEnd) {
|
||||
if (!dates.contains(date.value)) {
|
||||
lessons.add(Lesson(profileId, date.value.toLong()).apply {
|
||||
this.type = Lesson.TYPE_NO_LESSONS
|
||||
this.date = date.clone()
|
||||
})
|
||||
}
|
||||
|
||||
date.stepForward(0, 0, 1)
|
||||
}
|
||||
|
||||
d(TAG, "Clearing lessons between ${weekStart.stringY_m_d} and ${weekEnd.stringY_m_d} - timetable downloaded for $getDate")
|
||||
|
||||
data.lessonNewList.addAll(lessons)
|
||||
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
||||
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_TIMETABLE, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_GC = 1023
|
||||
const val ENDPOINT_LIBRUS_API_TEXT_GC = 1024
|
||||
const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GC = 1025
|
||||
const val ENDPOINT_LIBRUS_API_BEHAVIOUR_GC = 1026
|
||||
const val ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS = 1030
|
||||
const val ENDPOINT_LIBRUS_API_NORMAL_GRADES = 1031
|
||||
const val ENDPOINT_LIBRUS_API_POINT_GRADES = 1032
|
||||
const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES = 1033
|
||||
@ -97,6 +98,7 @@ val LibrusFeatures = listOf(
|
||||
ENDPOINT_LIBRUS_API_TEXT_GC to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GC to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_BEHAVIOUR_GC to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GRADES to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_POINT_GRADES to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES to LOGIN_METHOD_LIBRUS_API,
|
||||
|
@ -32,6 +32,13 @@ open class LibrusApi(open val data: DataLibrus) {
|
||||
|
||||
val callback = object : JsonCallbackHandler() {
|
||||
override fun onSuccess(json: JsonObject?, response: Response?) {
|
||||
if (response?.code() == HTTP_UNAVAILABLE) {
|
||||
data.error(ApiError(tag, ERROR_LIBRUS_API_MAINTENANCE)
|
||||
.withApiResponse(json)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
if (json == null && response?.parserErrorBody == null) {
|
||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||
.withResponse(response))
|
||||
@ -104,6 +111,7 @@ open class LibrusApi(open val data: DataLibrus) {
|
||||
.allowErrorCode(HTTP_BAD_REQUEST)
|
||||
.allowErrorCode(HTTP_FORBIDDEN)
|
||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||
.allowErrorCode(HTTP_UNAVAILABLE)
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
|
@ -85,6 +85,10 @@ class LibrusData(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grades)
|
||||
LibrusApiGrades(data, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grade_comments)
|
||||
LibrusApiGradeComments(data, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GC -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grade_categories)
|
||||
LibrusApiGradeCategories(data, onSuccess)
|
||||
|
@ -15,7 +15,6 @@ import org.jsoup.parser.Parser
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.io.StringWriter
|
||||
import javax.xml.parsers.DocumentBuilderFactory
|
||||
@ -43,19 +42,19 @@ open class LibrusMessages(open val data: DataLibrus) {
|
||||
val callback = object : TextCallbackHandler() {
|
||||
override fun onSuccess(text: String?, response: Response?) {
|
||||
if (text.isNullOrEmpty()) {
|
||||
data.error(ApiError(LibrusSynergia.TAG, ERROR_RESPONSE_EMPTY)
|
||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Finish error handling
|
||||
|
||||
if ("error" in text) {
|
||||
when ("<type>(.*)</type>".toRegex().find(text)?.get(1)) {
|
||||
"eAccessDeny" -> data.error(ApiError(tag, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED)
|
||||
.withResponse(response)
|
||||
.withApiResponse(text))
|
||||
}
|
||||
when {
|
||||
text.contains("<message>Niepoprawny login i/lub hasło.</message>") -> data.error(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_INVALID_LOGIN, response, text)
|
||||
text.contains("stop.png") -> data.error(TAG, ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED, response, text)
|
||||
text.contains("eAccessDeny") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
||||
text.contains("OffLine") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_MAINTENANCE, response, text)
|
||||
text.contains("<status>error</status>") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ERROR, response, text)
|
||||
text.contains("<type>eVarWhitThisNameNotExists</type>") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
||||
text.contains("<error>") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_OTHER, response, text)
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -14,7 +14,7 @@ import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
open class LibrusSynergia(open val data: DataLibrus) {
|
||||
companion object {
|
||||
const val TAG = "LibrusSynergia"
|
||||
private const val TAG = "LibrusSynergia"
|
||||
}
|
||||
|
||||
val profileId
|
||||
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-11-20
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.asJsonObjectList
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.getJsonArray
|
||||
import pl.szczodrzynski.edziennik.getLong
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
|
||||
class LibrusApiGradeComments(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiGradeComments"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, "Grades/Comments") { json ->
|
||||
|
||||
json.getJsonArray("Comments")?.asJsonObjectList()?.forEach { comment ->
|
||||
val id = comment.getLong("Id") ?: return@forEach
|
||||
val text = comment.getString("Text")
|
||||
|
||||
val gradeCategoryObject = GradeCategory(
|
||||
profileId,
|
||||
id,
|
||||
-1f,
|
||||
-1,
|
||||
text
|
||||
).apply {
|
||||
type = GradeCategory.TYPE_COMMENT
|
||||
}
|
||||
|
||||
data.gradeCategories.put(id, gradeCategoryObject)
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_NORMAL_GRADE
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
@ -42,12 +43,21 @@ class LibrusApiGrades(override val data: DataLibrus,
|
||||
weight = 0f
|
||||
}
|
||||
|
||||
val description = grade.getJsonArray("Comments")?.asJsonObjectList()?.let { comments ->
|
||||
if (comments.isNotEmpty()) {
|
||||
data.gradeCategories.singleOrNull {
|
||||
it.type == GradeCategory.TYPE_COMMENT
|
||||
&& it.categoryId == comments[0].asJsonObject.getLong("Id")
|
||||
}?.text
|
||||
} else null
|
||||
} ?: ""
|
||||
|
||||
val gradeObject = Grade(
|
||||
profileId,
|
||||
id,
|
||||
categoryName,
|
||||
color,
|
||||
"",
|
||||
description,
|
||||
name,
|
||||
value,
|
||||
weight,
|
||||
|
@ -17,6 +17,7 @@ import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||
|
||||
class LibrusApiTimetables(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
@ -29,9 +30,18 @@ class LibrusApiTimetables(override val data: DataLibrus,
|
||||
data.db.classroomDao().getAllNow(profileId).toSparseArray(data.classrooms) { it.id }
|
||||
}
|
||||
|
||||
val currentWeekStart = Date.getToday().let { it.stepForward(0, 0, -it.weekDay) }
|
||||
val currentWeekStart = Week.getWeekStart()
|
||||
|
||||
if (Date.getToday().weekDay > 4) {
|
||||
currentWeekStart.stepForward(0, 0, 7)
|
||||
}
|
||||
|
||||
val getDate = data.arguments?.getString("weekStart") ?: currentWeekStart.stringY_m_d
|
||||
apiGet(TAG, "Timetables?weekStart=$getDate") { json ->
|
||||
|
||||
val weekStart = Date.fromY_m_d(getDate)
|
||||
val weekEnd = weekStart.clone().stepForward(0, 0, 6)
|
||||
|
||||
apiGet(TAG, "Timetables?weekStart=${weekStart.stringY_m_d}") { json ->
|
||||
val days = json.getJsonObject("Timetable")
|
||||
|
||||
days?.entrySet()?.forEach { (dateString, dayEl) ->
|
||||
@ -57,8 +67,6 @@ class LibrusApiTimetables(override val data: DataLibrus,
|
||||
}
|
||||
}
|
||||
|
||||
val weekStart = Date.fromY_m_d(getDate)
|
||||
val weekEnd = weekStart.clone().stepForward(0, 0, 6)
|
||||
d(TAG, "Clearing lessons between ${weekStart.stringY_m_d} and ${weekEnd.stringY_m_d} - timetable downloaded for $getDate")
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
||||
@ -176,7 +184,7 @@ class LibrusApiTimetables(override val data: DataLibrus,
|
||||
}
|
||||
}
|
||||
|
||||
if (lessonObject.type != Lesson.TYPE_NORMAL) {
|
||||
if (lessonObject.type != Lesson.TYPE_NORMAL && lessonDate >= Date.getToday()) {
|
||||
data.metadataList.add(
|
||||
Metadata(
|
||||
data.profileId,
|
||||
|
@ -16,8 +16,7 @@ import pl.szczodrzynski.edziennik.getInt
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.getUnixDate
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.net.HttpURLConnection.HTTP_BAD_REQUEST
|
||||
import java.net.HttpURLConnection.HTTP_UNAUTHORIZED
|
||||
import java.net.HttpURLConnection.*
|
||||
|
||||
class LibrusLoginApi {
|
||||
companion object {
|
||||
@ -117,6 +116,13 @@ class LibrusLoginApi {
|
||||
|
||||
private val tokenCallback = object : JsonCallbackHandler() {
|
||||
override fun onSuccess(json: JsonObject?, response: Response?) {
|
||||
if (response?.code() == HTTP_UNAVAILABLE) {
|
||||
data.error(ApiError(TAG, ERROR_LIBRUS_API_MAINTENANCE)
|
||||
.withApiResponse(json)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
if (json == null) {
|
||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||
.withResponse(response))
|
||||
@ -176,6 +182,7 @@ class LibrusLoginApi {
|
||||
.post()
|
||||
.allowErrorCode(HTTP_BAD_REQUEST)
|
||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||
.allowErrorCode(HTTP_UNAVAILABLE)
|
||||
.callback(tokenCallback)
|
||||
.build()
|
||||
.enqueue()
|
||||
|
@ -6,20 +6,57 @@ package pl.szczodrzynski.edziennik.api.v2.librus.login
|
||||
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.body.MediaTypeUtils
|
||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import okhttp3.Cookie
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.getUnixDate
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.io.StringWriter
|
||||
import javax.xml.parsers.DocumentBuilderFactory
|
||||
import javax.xml.transform.OutputKeys
|
||||
import javax.xml.transform.TransformerFactory
|
||||
import javax.xml.transform.dom.DOMSource
|
||||
import javax.xml.transform.stream.StreamResult
|
||||
|
||||
class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "LoginLibrusMessages"
|
||||
}
|
||||
|
||||
private val callback by lazy { object : TextCallbackHandler() {
|
||||
override fun onSuccess(text: String?, response: Response?) {
|
||||
val location = response?.headers()?.get("Location")
|
||||
when {
|
||||
location?.contains("MultiDomainLogon") == true -> loginWithSynergia(location)
|
||||
location?.contains("AutoLogon") == true -> {
|
||||
saveSessionId(response, text)
|
||||
onSuccess()
|
||||
}
|
||||
|
||||
text?.contains("<status>ok</status>") == true -> {
|
||||
saveSessionId(response, text)
|
||||
onSuccess()
|
||||
}
|
||||
text?.contains("<message>Niepoprawny login i/lub hasło.</message>") == true -> data.error(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_INVALID_LOGIN, response, text)
|
||||
text?.contains("stop.png") == true -> data.error(TAG, ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED, response, text)
|
||||
text?.contains("eAccessDeny") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
||||
text?.contains("OffLine") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_MAINTENANCE, response, text)
|
||||
text?.contains("<status>error</status>") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ERROR, response, text)
|
||||
text?.contains("<type>eVarWhitThisNameNotExists</type>") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
||||
text?.contains("<error>") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_OTHER, response, text)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}}
|
||||
|
||||
init { run {
|
||||
if (data.profile == null) {
|
||||
data.error(ApiError(TAG, ERROR_PROFILE_MISSING))
|
||||
@ -41,7 +78,7 @@ class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
if (data.loginMethods.contains(LOGIN_METHOD_LIBRUS_SYNERGIA)) {
|
||||
loginWithSynergia()
|
||||
}
|
||||
else if (data.apiLogin != null && data.apiPassword != null && false) {
|
||||
else if (data.apiLogin != null && data.apiPassword != null) {
|
||||
loginWithCredentials()
|
||||
}
|
||||
else {
|
||||
@ -54,7 +91,44 @@ class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
* XML (Flash messages website) login method. Uses a Synergia login and password.
|
||||
*/
|
||||
private fun loginWithCredentials() {
|
||||
d(TAG, "Request: Librus/Login/Messages - $LIBRUS_MESSAGES_URL/Login")
|
||||
|
||||
val docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
|
||||
val doc = docBuilder.newDocument()
|
||||
val serviceElement = doc.createElement("service")
|
||||
val headerElement = doc.createElement("header")
|
||||
val dataElement = doc.createElement("data")
|
||||
val loginElement = doc.createElement("login")
|
||||
loginElement.appendChild(doc.createTextNode(data.apiLogin))
|
||||
dataElement.appendChild(loginElement)
|
||||
val passwordElement = doc.createElement("login")
|
||||
passwordElement.appendChild(doc.createTextNode(data.apiPassword))
|
||||
dataElement.appendChild(passwordElement)
|
||||
val keyStrokeElement = doc.createElement("KeyStroke")
|
||||
val keysElement = doc.createElement("Keys")
|
||||
val upElement = doc.createElement("Up")
|
||||
keysElement.appendChild(upElement)
|
||||
val downElement = doc.createElement("Down")
|
||||
keysElement.appendChild(downElement)
|
||||
keyStrokeElement.appendChild(keysElement)
|
||||
dataElement.appendChild(keyStrokeElement)
|
||||
serviceElement.appendChild(headerElement)
|
||||
serviceElement.appendChild(dataElement)
|
||||
doc.appendChild(serviceElement)
|
||||
val transformer = TransformerFactory.newInstance().newTransformer()
|
||||
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes")
|
||||
val stringWriter = StringWriter()
|
||||
transformer.transform(DOMSource(doc), StreamResult(stringWriter))
|
||||
val requestXml = stringWriter.toString()
|
||||
|
||||
Request.builder()
|
||||
.url("$LIBRUS_MESSAGES_URL/Login")
|
||||
.userAgent(SYNERGIA_USER_AGENT)
|
||||
.setTextBody(requestXml, MediaTypeUtils.APPLICATION_XML)
|
||||
.post()
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -63,37 +137,6 @@ class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
private fun loginWithSynergia(url: String = "https://synergia.librus.pl/wiadomosci2") {
|
||||
d(TAG, "Request: Librus/Login/Messages - $url")
|
||||
|
||||
val callback = object : TextCallbackHandler() {
|
||||
override fun onSuccess(text: String?, response: Response?) {
|
||||
val location = response?.headers()?.get("Location")
|
||||
when {
|
||||
location?.contains("MultiDomainLogon") == true -> loginWithSynergia(location)
|
||||
location?.contains("AutoLogon") == true -> {
|
||||
var sessionId = data.app.cookieJar.getCookie("wiadomosci.librus.pl", "DZIENNIKSID")
|
||||
sessionId = sessionId?.replace("-MAINT", "")
|
||||
if (sessionId == null) {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_NO_SESSION_ID)
|
||||
.withResponse(response)
|
||||
.withApiResponse(text))
|
||||
return
|
||||
}
|
||||
data.messagesSessionId = sessionId
|
||||
data.messagesSessionIdExpiryTime = response.getUnixDate() + 45 * 60 /* 45min */
|
||||
onSuccess()
|
||||
}
|
||||
|
||||
text?.contains("eAccessDeny") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
||||
text?.contains("stop.png") == true -> data.error(TAG, ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED, response, text)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}
|
||||
|
||||
Request.builder()
|
||||
.url(url)
|
||||
.userAgent(SYNERGIA_USER_AGENT)
|
||||
@ -103,4 +146,17 @@ class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
private fun saveSessionId(response: Response?, text: String?) {
|
||||
var sessionId = data.app.cookieJar.getCookie("wiadomosci.librus.pl", "DZIENNIKSID")
|
||||
sessionId = sessionId?.replace("-MAINT", "") // dunno what's this
|
||||
if (sessionId == null) {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_NO_SESSION_ID)
|
||||
.withResponse(response)
|
||||
.withApiResponse(text))
|
||||
return
|
||||
}
|
||||
data.messagesSessionId = sessionId
|
||||
data.messagesSessionIdExpiryTime = response.getUnixDate() + 45 * 60 /* 45min */
|
||||
}
|
||||
}
|
@ -99,6 +99,14 @@ class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
.post()
|
||||
.callback(object : JsonCallbackHandler() {
|
||||
override fun onSuccess(json: JsonObject?, response: Response) {
|
||||
val location = response.headers()?.get("Location")
|
||||
if (location == "http://localhost/bar?command=close") {
|
||||
data.error(ApiError(TAG, ERROR_LIBRUS_PORTAL_MAINTENANCE)
|
||||
.withApiResponse(json)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
if (json == null) {
|
||||
if (response.parserErrorBody?.contains("wciąż nieaktywne") == true) {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED)
|
||||
@ -120,7 +128,7 @@ class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
|
||||
override fun onFailure(response: Response, throwable: Throwable) {
|
||||
if (response.code() == 403 || response.code() == 401) {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_DATA_INVALID)
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
return
|
||||
|
@ -7,7 +7,6 @@ package pl.szczodrzynski.edziennik.api.v2.librus.login
|
||||
import com.google.gson.JsonObject
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import okhttp3.Cookie
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
@ -16,7 +15,6 @@ import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.getUnixDate
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.net.HttpURLConnection
|
||||
|
||||
@ -86,6 +84,13 @@ class LibrusLoginSynergia(override val data: DataLibrus, val onSuccess: () -> Un
|
||||
val callback = object : TextCallbackHandler() {
|
||||
override fun onSuccess(json: String?, response: Response?) {
|
||||
val location = response?.headers()?.get("Location")
|
||||
if (location?.endsWith("przerwa_techniczna") == true) {
|
||||
data.error(ApiError(TAG, ERROR_LIBRUS_SYNERGIA_MAINTENANCE)
|
||||
.withApiResponse(json)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
if (location?.endsWith("centrum_powiadomien") == true) {
|
||||
val sessionId = data.app.cookieJar.getCookie("synergia.librus.pl", "DZIENNIKSID")
|
||||
if (sessionId == null) {
|
||||
|
@ -10,8 +10,10 @@ import pl.szczodrzynski.edziennik.api.v2.CODE_INTERNAL_LIBRUS_ACCOUNT_410
|
||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.MobidziennikData
|
||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.web.MobidziennikWebGetMessage
|
||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.firstlogin.MobidziennikFirstLogin
|
||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.login.MobidziennikLogin
|
||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.login.MobidziennikLoginWeb
|
||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennikLoginMethods
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.api.v2.prepare
|
||||
@ -63,7 +65,11 @@ class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginSto
|
||||
}
|
||||
|
||||
override fun getMessage(message: MessageFull) {
|
||||
|
||||
MobidziennikLoginWeb(data) {
|
||||
MobidziennikWebGetMessage(data, message) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun markAllAnnouncementsAsRead() {
|
||||
|
@ -75,7 +75,7 @@ class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
|
||||
}
|
||||
}
|
||||
|
||||
if (it.type != Lesson.TYPE_NORMAL) {
|
||||
if (it.type != Lesson.TYPE_NORMAL && date >= Date.getToday()) {
|
||||
data.metadataList.add(
|
||||
Metadata(
|
||||
data.profileId,
|
||||
@ -195,4 +195,4 @@ class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-18.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.web
|
||||
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.api.v2.Regexes
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.MessageGetEvent
|
||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.MobidziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipientFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.singleOrNull
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.monthFromName
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class MobidziennikWebGetMessage(
|
||||
override val data: DataMobidziennik,
|
||||
private val message: MessageFull,
|
||||
val onSuccess: () -> Unit) : MobidziennikWeb(data) {
|
||||
companion object {
|
||||
private const val TAG = "MobidziennikWebGetMessage"
|
||||
}
|
||||
|
||||
init {
|
||||
val typeUrl = if (message.type == Message.TYPE_SENT)
|
||||
"wiadwyslana"
|
||||
else
|
||||
"wiadodebrana"
|
||||
webGet(TAG, "/dziennik/$typeUrl/?id=${message.id}") { text ->
|
||||
MobidziennikLuckyNumberExtractor(data, text)
|
||||
|
||||
val messageRecipientList = mutableListOf<MessageRecipientFull>()
|
||||
|
||||
val doc = Jsoup.parse(text)
|
||||
|
||||
val content = doc.select("#content").first()
|
||||
|
||||
val body = content.select(".wiadomosc_tresc").first()
|
||||
|
||||
if (message.type == TYPE_RECEIVED) {
|
||||
var readDate = System.currentTimeMillis()
|
||||
Regexes.MOBIDZIENNIK_MESSAGE_READ_DATE.find(body.html())?.let {
|
||||
val date = Date(
|
||||
it[3].toIntOrNull() ?: 2019,
|
||||
monthFromName(it[2]),
|
||||
it[1].toIntOrNull() ?: 1
|
||||
)
|
||||
val time = Time.fromH_m_s(
|
||||
it[4] // TODO blank string safety
|
||||
)
|
||||
readDate = date.combineWith(time)
|
||||
}
|
||||
|
||||
val recipient = MessageRecipientFull(
|
||||
profileId,
|
||||
-1,
|
||||
-1,
|
||||
readDate,
|
||||
message.id
|
||||
)
|
||||
|
||||
recipient.fullName = profile?.accountNameLong ?: profile?.studentNameLong
|
||||
|
||||
messageRecipientList.add(recipient)
|
||||
} else {
|
||||
message.senderId = -1
|
||||
message.senderReplyId = -1
|
||||
|
||||
content.select("table.spis tr:has(td)")?.forEach { recipientEl ->
|
||||
val senderEl = recipientEl.select("td:eq(0)").first()
|
||||
val senderName = senderEl.text()
|
||||
|
||||
val teacher = data.teacherList.singleOrNull { it.fullNameLastFirst == senderName }
|
||||
val receiverId = teacher?.id ?: -1
|
||||
|
||||
var readDate = 0L
|
||||
val isReadEl = recipientEl.select("td:eq(2)").first()
|
||||
if (isReadEl.ownText() != "NIE") {
|
||||
val readDateEl = recipientEl.select("td:eq(3) small").first()
|
||||
Regexes.MOBIDZIENNIK_MESSAGE_SENT_READ_DATE.find(readDateEl.ownText())?.let {
|
||||
val date = Date(
|
||||
it[3].toIntOrNull() ?: 2019,
|
||||
monthFromName(it[2]),
|
||||
it[1].toIntOrNull() ?: 1
|
||||
)
|
||||
val time = Time.fromH_m_s(
|
||||
it[4] // TODO blank string safety
|
||||
)
|
||||
readDate = date.combineWith(time)
|
||||
}
|
||||
}
|
||||
|
||||
val recipient = MessageRecipientFull(
|
||||
profileId,
|
||||
receiverId,
|
||||
-1,
|
||||
readDate,
|
||||
message.id
|
||||
)
|
||||
|
||||
recipient.fullName = teacher?.fullName ?: "?"
|
||||
|
||||
messageRecipientList.add(recipient)
|
||||
}
|
||||
}
|
||||
|
||||
// this line removes the sender and read date details
|
||||
body.select("div").remove()
|
||||
|
||||
// this needs to be at the end
|
||||
message.apply {
|
||||
this.body = body.html()
|
||||
|
||||
clearAttachments()
|
||||
content.select("ul li").map { it.select("a").first() }.forEach {
|
||||
val attachmentName = it.ownText()
|
||||
Regexes.MOBIDZIENNIK_MESSAGE_ATTACHMENT.find(it.outerHtml())?.let { match ->
|
||||
val attachmentId = match[1].toLong()
|
||||
var size = match[2].toFloatOrNull() ?: 0f
|
||||
when (match[3]) {
|
||||
"K" -> size *= 1024f
|
||||
"M" -> size *= 1024f * 1024f
|
||||
"G" -> size *= 1024f * 1024f * 1024f
|
||||
}
|
||||
message.addAttachment(attachmentId, attachmentName, size.toLong())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!message.seen) { // TODO discover why this monstrosity instead of MetadataDao.setSeen
|
||||
data.messageMetadataList.add(Metadata(
|
||||
message.profileId,
|
||||
Metadata.TYPE_MESSAGE,
|
||||
message.id,
|
||||
true,
|
||||
true,
|
||||
message.addedDate
|
||||
))
|
||||
}
|
||||
|
||||
message.recipients = messageRecipientList
|
||||
data.messageRecipientList.addAll(messageRecipientList)
|
||||
data.messageList.add(message)
|
||||
|
||||
EventBus.getDefault().postSticky(MessageGetEvent(message))
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -7,15 +7,14 @@ package pl.szczodrzynski.edziennik.api.v2.vulcan
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_VULCAN_API
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.Data
|
||||
import pl.szczodrzynski.edziennik.currentTimeUnix
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
||||
|
||||
class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
|
||||
|
||||
fun isApiLoginValid() = apiCertificateExpiryTime-30 > currentTimeUnix()
|
||||
&& apiCertificateKey.isNotNullNorEmpty()
|
||||
fun isApiLoginValid() = /*apiCertificateExpiryTime-30 > currentTimeUnix()
|
||||
&&*/ apiCertificateKey.isNotNullNorEmpty()
|
||||
&& apiCertificatePrivate.isNotNullNorEmpty()
|
||||
&& symbol.isNotNullNorEmpty()
|
||||
|
||||
@ -165,6 +164,8 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
"GD1" -> "https://uonetplus-komunikacja.edu.gdansk.pl"
|
||||
"KA1" -> "https://uonetplus-komunikacja.mcuw.katowice.eu"
|
||||
"KA2" -> "https://uonetplus-komunikacja-test.mcuw.katowice.eu"
|
||||
"LU1" -> "https://uonetplus-komunikacja.edu.lublin.eu"
|
||||
"LU2" -> "https://test-uonetplus-komunikacja.edu.lublin.eu"
|
||||
"P03" -> "https://efeb-komunikacja-pro-efebmobile.pro.vulcan.pl"
|
||||
"P01" -> "http://efeb-komunikacja.pro-hudson.win.vulcan.pl"
|
||||
"P02" -> "http://efeb-komunikacja.pro-hudsonrc.win.vulcan.pl"
|
||||
@ -173,7 +174,7 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
"SZ9" -> "http://vulcan.szkolny.eu"
|
||||
else -> null
|
||||
}
|
||||
return if (url != null) "$url/$symbol" else null
|
||||
return if (url != null) "$url/$symbol" else loginStore.getLoginData("apiUrl", null)
|
||||
}
|
||||
|
||||
val fullApiUrl: String?
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.vulcan.data.api
|
||||
|
||||
import androidx.core.util.set
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.Regexes
|
||||
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_TIMETABLE
|
||||
@ -14,173 +15,197 @@ import pl.szczodrzynski.edziennik.api.v2.vulcan.data.VulcanApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.subjects.Subject
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.crc16
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||
|
||||
class VulcanApiTimetable(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
|
||||
companion object {
|
||||
const val TAG = "VulcanApiTimetable"
|
||||
}
|
||||
|
||||
init {
|
||||
data.profile?.also { profile ->
|
||||
val currentWeekStart = Date.getToday().let { it.stepForward(0, 0, -it.weekDay) }
|
||||
val getDate = data.arguments?.getString("weekStart") ?: currentWeekStart.stringY_m_d
|
||||
init { data.profile?.also { profile ->
|
||||
val currentWeekStart = Week.getWeekStart()
|
||||
val getDate = data.arguments?.getString("weekStart") ?: currentWeekStart.stringY_m_d
|
||||
|
||||
val weekStart = Date.fromY_m_d(getDate)
|
||||
val weekEnd = weekStart.clone().stepForward(0, 0, 6)
|
||||
val weekStart = Date.fromY_m_d(getDate)
|
||||
|
||||
apiGet(TAG, VULCAN_API_ENDPOINT_TIMETABLE, parameters = mapOf(
|
||||
"DataPoczatkowa" to weekStart.stringY_m_d,
|
||||
"DataKoncowa" to weekEnd.stringY_m_d,
|
||||
"IdUczen" to data.studentId,
|
||||
"IdOddzial" to data.studentClassId,
|
||||
"IdOkresKlasyfikacyjny" to data.studentSemesterId
|
||||
)) { json, _ ->
|
||||
val dates: MutableSet<Int> = mutableSetOf()
|
||||
val lessons: MutableList<Lesson> = mutableListOf()
|
||||
if (Date.getToday().weekDay > 4 && weekStart == currentWeekStart) {
|
||||
weekStart.stepForward(0, 0, 7)
|
||||
}
|
||||
|
||||
json.getJsonArray("Data")?.asJsonObjectList()?.forEach { lesson ->
|
||||
val lessonDate = Date.fromY_m_d(lesson.getString("DzienTekst"))
|
||||
val lessonNumber = lesson.getInt("NumerLekcji")
|
||||
val lessonRange = data.lessonRanges.singleOrNull { it.lessonNumber == lessonNumber }
|
||||
val startTime = lessonRange?.startTime
|
||||
val endTime = lessonRange?.endTime
|
||||
val teacherId = lesson.getLong("IdPracownik")
|
||||
val teamId = data.studentClassId.toLong()
|
||||
val classroom = lesson.getString("Classroom")
|
||||
val weekEnd = weekStart.clone().stepForward(0, 0, 6)
|
||||
|
||||
val oldTeacherId = lesson.getLong("IdPracownikOld")
|
||||
apiGet(TAG, VULCAN_API_ENDPOINT_TIMETABLE, parameters = mapOf(
|
||||
"DataPoczatkowa" to weekStart.stringY_m_d,
|
||||
"DataKoncowa" to weekEnd.stringY_m_d,
|
||||
"IdUczen" to data.studentId,
|
||||
"IdOddzial" to data.studentClassId,
|
||||
"IdOkresKlasyfikacyjny" to data.studentSemesterId
|
||||
)) { json, _ ->
|
||||
val dates = mutableSetOf<Int>()
|
||||
val lessons = mutableListOf<Lesson>()
|
||||
|
||||
val changeAnnotation = lesson.getString("AdnotacjaOZmianie") ?: ""
|
||||
val type = when {
|
||||
changeAnnotation.startsWith("(przeniesiona z") -> Lesson.TYPE_SHIFTED_TARGET
|
||||
changeAnnotation.startsWith("(przeniesiona na") -> Lesson.TYPE_SHIFTED_SOURCE
|
||||
changeAnnotation.startsWith("(zastępstwo") -> Lesson.TYPE_CHANGE
|
||||
lesson.getBoolean("PrzekreslonaNazwa") == true -> Lesson.TYPE_CANCELLED
|
||||
else -> Lesson.TYPE_NORMAL
|
||||
json.getJsonArray("Data")?.asJsonObjectList()?.forEach { lesson ->
|
||||
if (lesson.getBoolean("PlanUcznia") != true)
|
||||
return@forEach
|
||||
val lessonDate = Date.fromY_m_d(lesson.getString("DzienTekst"))
|
||||
val lessonNumber = lesson.getInt("NumerLekcji")
|
||||
val lessonRange = data.lessonRanges.singleOrNull { it.lessonNumber == lessonNumber }
|
||||
val startTime = lessonRange?.startTime
|
||||
val endTime = lessonRange?.endTime
|
||||
val teacherId = lesson.getLong("IdPracownik")
|
||||
val classroom = lesson.getString("Sala")
|
||||
|
||||
val oldTeacherId = lesson.getLong("IdPracownikOld")
|
||||
|
||||
val changeAnnotation = lesson.getString("AdnotacjaOZmianie") ?: ""
|
||||
val type = when {
|
||||
changeAnnotation.startsWith("(przeniesiona z") -> Lesson.TYPE_SHIFTED_TARGET
|
||||
changeAnnotation.startsWith("(przeniesiona na") -> Lesson.TYPE_SHIFTED_SOURCE
|
||||
changeAnnotation.startsWith("(zastępstwo") -> Lesson.TYPE_CHANGE
|
||||
lesson.getBoolean("PrzekreslonaNazwa") == true -> Lesson.TYPE_CANCELLED
|
||||
else -> Lesson.TYPE_NORMAL
|
||||
}
|
||||
|
||||
val teamId = lesson.getString("PodzialSkrot")?.let { teamName ->
|
||||
val name = "${data.teamClass?.name} $teamName"
|
||||
val id = name.crc16().toLong()
|
||||
var team = data.teamList.singleOrNull { it.name == name }
|
||||
if (team == null) {
|
||||
team = Team(
|
||||
profileId,
|
||||
id,
|
||||
name,
|
||||
Team.TYPE_VIRTUAL,
|
||||
"${data.schoolName}:$name",
|
||||
teacherId ?: oldTeacherId ?: -1
|
||||
)
|
||||
data.teamList[id] = team
|
||||
}
|
||||
team.id
|
||||
} ?: data.studentClassId.toLong()
|
||||
|
||||
val subjectId = lesson.getLong("IdPrzedmiot")?.let {
|
||||
when (it) {
|
||||
0L -> {
|
||||
val subjectName = lesson.getString("PrzedmiotNazwa") ?: ""
|
||||
val subjectId = lesson.getLong("IdPrzedmiot")?.let {
|
||||
when (it) {
|
||||
0L -> {
|
||||
val subjectName = lesson.getString("PrzedmiotNazwa") ?: ""
|
||||
|
||||
data.subjectList.singleOrNull { subject -> subject.longName == subjectName }?.id
|
||||
?: {
|
||||
/**
|
||||
* CREATE A NEW SUBJECT IF IT DOESN'T EXIST
|
||||
*/
|
||||
data.subjectList.singleOrNull { subject -> subject.longName == subjectName }?.id
|
||||
?: {
|
||||
/**
|
||||
* CREATE A NEW SUBJECT IF IT DOESN'T EXIST
|
||||
*/
|
||||
|
||||
val subjectObject = Subject(
|
||||
profileId,
|
||||
-1 * crc16(subjectName.toByteArray()).toLong(),
|
||||
subjectName,
|
||||
subjectName
|
||||
)
|
||||
data.subjectList.put(subjectObject.id, subjectObject)
|
||||
subjectObject.id
|
||||
}.invoke()
|
||||
}
|
||||
else -> it
|
||||
val subjectObject = Subject(
|
||||
profileId,
|
||||
-1 * crc16(subjectName.toByteArray()).toLong(),
|
||||
subjectName,
|
||||
subjectName
|
||||
)
|
||||
data.subjectList.put(subjectObject.id, subjectObject)
|
||||
subjectObject.id
|
||||
}.invoke()
|
||||
}
|
||||
else -> it
|
||||
}
|
||||
}
|
||||
|
||||
val id = lessonDate.combineWith(startTime) / 6L * 10L + (lesson.hashCode() and 0xFFFF)
|
||||
|
||||
val lessonObject = Lesson(profileId, id).apply {
|
||||
this.type = type
|
||||
|
||||
when (type) {
|
||||
Lesson.TYPE_NORMAL, Lesson.TYPE_CHANGE, Lesson.TYPE_SHIFTED_TARGET -> {
|
||||
this.date = lessonDate
|
||||
this.lessonNumber = lessonNumber
|
||||
this.startTime = startTime
|
||||
this.endTime = endTime
|
||||
this.subjectId = subjectId
|
||||
this.teacherId = teacherId
|
||||
this.teamId = teamId
|
||||
this.classroom = classroom
|
||||
|
||||
this.oldTeacherId = oldTeacherId
|
||||
}
|
||||
|
||||
Lesson.TYPE_CANCELLED, Lesson.TYPE_SHIFTED_SOURCE -> {
|
||||
this.oldDate = lessonDate
|
||||
this.oldLessonNumber = lessonNumber
|
||||
this.oldStartTime = startTime
|
||||
this.oldEndTime = endTime
|
||||
this.oldSubjectId = subjectId
|
||||
this.oldTeacherId = teacherId
|
||||
this.oldTeamId = teamId
|
||||
this.oldClassroom = classroom
|
||||
}
|
||||
}
|
||||
|
||||
val id = lessonDate.combineWith(startTime) / 6L * 10L + (lesson.hashCode() and 0xFFFF)
|
||||
if (type == Lesson.TYPE_SHIFTED_SOURCE || type == Lesson.TYPE_SHIFTED_TARGET) {
|
||||
val shift = Regexes.VULCAN_SHITFT_ANNOTATION.find(changeAnnotation)
|
||||
val oldLessonNumber = shift?.get(2)?.toInt()
|
||||
val oldLessonDate = shift?.get(3)?.let { Date.fromd_m_Y(it) }
|
||||
|
||||
val lessonObject = Lesson(profileId, id).apply {
|
||||
this.type = type
|
||||
val oldLessonRange = data.lessonRanges.singleOrNull { it.lessonNumber == oldLessonNumber }
|
||||
val oldStartTime = oldLessonRange?.startTime
|
||||
val oldEndTime = oldLessonRange?.endTime
|
||||
|
||||
when (type) {
|
||||
Lesson.TYPE_NORMAL, Lesson.TYPE_CHANGE, Lesson.TYPE_SHIFTED_TARGET -> {
|
||||
this.date = lessonDate
|
||||
this.lessonNumber = lessonNumber
|
||||
this.startTime = startTime
|
||||
this.endTime = endTime
|
||||
this.subjectId = subjectId
|
||||
this.teacherId = teacherId
|
||||
this.teamId = teamId
|
||||
this.classroom = classroom
|
||||
|
||||
this.oldTeacherId = oldTeacherId
|
||||
Lesson.TYPE_SHIFTED_SOURCE -> {
|
||||
this.lessonNumber = oldLessonNumber
|
||||
this.date = oldLessonDate
|
||||
this.startTime = oldStartTime
|
||||
this.endTime = oldEndTime
|
||||
}
|
||||
|
||||
Lesson.TYPE_CANCELLED, Lesson.TYPE_SHIFTED_SOURCE -> {
|
||||
this.oldDate = lessonDate
|
||||
this.oldLessonNumber = lessonNumber
|
||||
this.oldStartTime = startTime
|
||||
this.oldEndTime = endTime
|
||||
this.oldSubjectId = subjectId
|
||||
this.oldTeacherId = teacherId
|
||||
this.oldTeamId = teamId
|
||||
this.oldClassroom = classroom
|
||||
}
|
||||
}
|
||||
|
||||
if (type == Lesson.TYPE_SHIFTED_SOURCE || type == Lesson.TYPE_SHIFTED_TARGET) {
|
||||
val shift = Regexes.VULCAN_SHITFT_ANNOTATION.find(changeAnnotation)
|
||||
val oldLessonNumber = shift?.get(2)?.toInt()
|
||||
val oldLessonDate = shift?.get(3)?.let { Date.fromd_m_Y(it) }
|
||||
|
||||
val oldLessonRange = data.lessonRanges.singleOrNull { it.lessonNumber == oldLessonNumber }
|
||||
val oldStartTime = oldLessonRange?.startTime
|
||||
val oldEndTime = oldLessonRange?.endTime
|
||||
|
||||
when (type) {
|
||||
Lesson.TYPE_SHIFTED_SOURCE -> {
|
||||
this.lessonNumber = oldLessonNumber
|
||||
this.date = oldLessonDate
|
||||
this.startTime = oldStartTime
|
||||
this.endTime = oldEndTime
|
||||
}
|
||||
|
||||
Lesson.TYPE_SHIFTED_TARGET -> {
|
||||
this.oldLessonNumber = oldLessonNumber
|
||||
this.oldDate = oldLessonDate
|
||||
this.oldStartTime = oldStartTime
|
||||
this.oldEndTime = oldEndTime
|
||||
}
|
||||
Lesson.TYPE_SHIFTED_TARGET -> {
|
||||
this.oldLessonNumber = oldLessonNumber
|
||||
this.oldDate = oldLessonDate
|
||||
this.oldStartTime = oldStartTime
|
||||
this.oldEndTime = oldEndTime
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type != Lesson.TYPE_NORMAL) {
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_LESSON_CHANGE,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
|
||||
dates.add(lessonDate.value)
|
||||
lessons.add(lessonObject)
|
||||
}
|
||||
|
||||
val date: Date = weekStart.clone()
|
||||
while (date <= weekEnd) {
|
||||
if (!dates.contains(date.value)) {
|
||||
lessons.add(Lesson(profileId, date.value.toLong()).apply {
|
||||
this.type = Lesson.TYPE_NO_LESSONS
|
||||
this.date = date.clone()
|
||||
})
|
||||
}
|
||||
|
||||
date.stepForward(0, 0, 1)
|
||||
if (type != Lesson.TYPE_NORMAL && lessonDate >= Date.getToday()) {
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_LESSON_CHANGE,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
|
||||
d(TAG, "Clearing lessons between ${weekStart.stringY_m_d} and ${weekEnd.stringY_m_d} - timetable downloaded for $getDate")
|
||||
|
||||
data.lessonNewList.addAll(lessons)
|
||||
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
||||
|
||||
data.setSyncNext(ENDPOINT_VULCAN_API_TIMETABLE, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
dates.add(lessonDate.value)
|
||||
lessons.add(lessonObject)
|
||||
}
|
||||
|
||||
val date: Date = weekStart.clone()
|
||||
while (date <= weekEnd) {
|
||||
if (!dates.contains(date.value)) {
|
||||
lessons.add(Lesson(profileId, date.value.toLong()).apply {
|
||||
this.type = Lesson.TYPE_NO_LESSONS
|
||||
this.date = date.clone()
|
||||
})
|
||||
}
|
||||
|
||||
date.stepForward(0, 0, 1)
|
||||
}
|
||||
|
||||
d(TAG, "Clearing lessons between ${weekStart.stringY_m_d} and ${weekEnd.stringY_m_d} - timetable downloaded for $getDate")
|
||||
|
||||
data.lessonNewList.addAll(lessons)
|
||||
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
||||
|
||||
data.setSyncNext(ENDPOINT_VULCAN_API_TIMETABLE, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
@ -38,10 +38,12 @@ class VulcanLoginApi(val data: DataVulcan, val onSuccess: () -> Unit) {
|
||||
if (data.apiToken?.get(0) == 'F') VULCAN_API_PASSWORD_FAKELOG else VULCAN_API_PASSWORD,
|
||||
data.apiCertificatePfx ?: ""
|
||||
)
|
||||
onSuccess()
|
||||
return@run
|
||||
data.loginStore.removeLoginData("certificatePfx")
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
} finally {
|
||||
onSuccess()
|
||||
return@run
|
||||
}
|
||||
}
|
||||
if (data.symbol.isNotNullNorEmpty() && data.apiToken.isNotNullNorEmpty() && data.apiPin.isNotNullNorEmpty()) {
|
||||
|
@ -1,10 +1,10 @@
|
||||
package pl.szczodrzynski.edziennik.data.db.modules.grades;
|
||||
|
||||
import androidx.room.Entity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.room.Entity;
|
||||
|
||||
@Entity(tableName = "gradeCategories",
|
||||
primaryKeys = {"profileId", "categoryId"})
|
||||
public class GradeCategory {
|
||||
@ -25,6 +25,9 @@ public class GradeCategory {
|
||||
*/
|
||||
public int type = 0;
|
||||
|
||||
public static final int TYPE_NORMAL = 0;
|
||||
public static final int TYPE_COMMENT = 1;
|
||||
|
||||
public GradeCategory(int profileId, long categoryId, float weight, int color, String text) {
|
||||
this.profileId = profileId;
|
||||
this.categoryId = categoryId;
|
||||
|
@ -21,7 +21,10 @@ interface NotificationDao {
|
||||
@Query("DELETE FROM notifications WHERE profileId = :profileId")
|
||||
fun clear(profileId: Int)
|
||||
|
||||
@Query("SELECT * FROM notifications")
|
||||
@Query("DELETE FROM notifications")
|
||||
fun clearAll()
|
||||
|
||||
@Query("SELECT * FROM notifications ORDER BY addedDate DESC")
|
||||
fun getAll(): LiveData<List<Notification>>
|
||||
|
||||
@Query("SELECT * FROM notifications")
|
||||
|
@ -38,16 +38,16 @@ interface TimetableDao {
|
||||
@Query("DELETE FROM timetable WHERE profileId = :profileId")
|
||||
fun clear(profileId: Int)
|
||||
|
||||
@Query("DELETE FROM timetable WHERE profileId = :profileId AND (type != 3 AND date >= :dateFrom) OR ((type = 3 OR type = 1) AND oldDate >= :dateFrom)")
|
||||
@Query("DELETE FROM timetable WHERE profileId = :profileId AND ((type != 3 AND date >= :dateFrom) OR ((type = 3 OR type = 1) AND oldDate >= :dateFrom))")
|
||||
fun clearFromDate(profileId: Int, dateFrom: Date)
|
||||
@Query("DELETE FROM timetable WHERE profileId = :profileId AND (type != 3 AND date <= :dateTo) OR ((type = 3 OR type = 1) AND oldDate <= :dateTo)")
|
||||
@Query("DELETE FROM timetable WHERE profileId = :profileId AND ((type != 3 AND date <= :dateTo) OR ((type = 3 OR type = 1) AND oldDate <= :dateTo))")
|
||||
fun clearToDate(profileId: Int, dateTo: Date)
|
||||
@Query("DELETE FROM timetable WHERE profileId = :profileId AND (type != 3 AND date >= :dateFrom AND date <= :dateTo) OR ((type = 3 OR type = 1) AND oldDate >= :dateFrom AND oldDate <= :dateTo)")
|
||||
@Query("DELETE FROM timetable WHERE profileId = :profileId AND ((type != 3 AND date >= :dateFrom AND date <= :dateTo) OR ((type = 3 OR type = 1) AND oldDate >= :dateFrom AND oldDate <= :dateTo))")
|
||||
fun clearBetweenDates(profileId: Int, dateFrom: Date, dateTo: Date)
|
||||
|
||||
@Query("""
|
||||
$QUERY
|
||||
WHERE timetable.profileId = :profileId AND (type != 3 AND date = :date) OR ((type = 3 OR type = 1) AND oldDate = :date)
|
||||
WHERE timetable.profileId = :profileId AND ((type != 3 AND date = :date) OR ((type = 3 OR type = 1) AND oldDate = :date))
|
||||
ORDER BY id, type
|
||||
""")
|
||||
fun getForDate(profileId: Int, date: Date) : LiveData<List<LessonFull>>
|
||||
@ -58,7 +58,15 @@ interface TimetableDao {
|
||||
ORDER BY id, type
|
||||
LIMIT 1
|
||||
""")
|
||||
fun getNextWithSubject(profileId: Int, today: Date, subjectId: Long) : LiveData<LessonFull>
|
||||
fun getNextWithSubject(profileId: Int, today: Date, subjectId: Long) : LiveData<LessonFull?>
|
||||
|
||||
@Query("""
|
||||
$QUERY
|
||||
WHERE timetable.profileId = :profileId AND ((type != 3 AND date > :today) OR ((type = 3 OR type = 1) AND oldDate > :today)) AND timetable.subjectId = :subjectId AND timetable.teamId = :teamId
|
||||
ORDER BY id, type
|
||||
LIMIT 1
|
||||
""")
|
||||
fun getNextWithSubjectAndTeam(profileId: Int, today: Date, subjectId: Long, teamId: Long): LiveData<LessonFull?>
|
||||
|
||||
@Query("""
|
||||
$QUERY
|
||||
|
@ -125,19 +125,22 @@ public class BootReceiver extends BroadcastReceiver {
|
||||
String updateUrl = result.get("update_url").getAsString();
|
||||
String updateFilename = result.get("update_filename").getAsString();
|
||||
boolean updateMandatory = result.get("update_mandatory").getAsBoolean();
|
||||
boolean updateDirect = result.get("update_direct").getAsBoolean();
|
||||
|
||||
if (app.appConfig.updateVersion == null || !app.appConfig.updateVersion.equals(updateVersion)) {
|
||||
app.appConfig.updateVersion = updateVersion;
|
||||
app.appConfig.updateUrl = updateUrl;
|
||||
app.appConfig.updateFilename = updateFilename;
|
||||
app.appConfig.updateMandatory = updateMandatory;
|
||||
app.appConfig.updateDirect = updateDirect;
|
||||
app.saveConfig();
|
||||
}
|
||||
if (!UPDATES_ON_PLAY_STORE || intent.getBooleanExtra("UserChecked", false)) {
|
||||
app.notifier.notificationUpdatesShow(
|
||||
updateVersion,
|
||||
updateUrl,
|
||||
updateFilename);
|
||||
updateFilename,
|
||||
updateDirect);
|
||||
}
|
||||
} else {
|
||||
if (app.appConfig.updateVersion == null || !app.appConfig.updateVersion.equals("")) {
|
||||
@ -259,7 +262,7 @@ public class BootReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent) {
|
||||
if (UPDATES_ON_PLAY_STORE) {
|
||||
if (UPDATES_ON_PLAY_STORE && !intent.getBooleanExtra("update_direct", false)) {
|
||||
Utils.openGooglePlay(this, "pl.szczodrzynski.edziennik");
|
||||
return;
|
||||
}
|
||||
@ -270,7 +273,8 @@ public class BootReceiver extends BroadcastReceiver {
|
||||
app.notifier.notificationUpdatesShow(
|
||||
intent.getStringExtra("update_version"),
|
||||
intent.getStringExtra("update_url"),
|
||||
intent.getStringExtra("update_filename"));
|
||||
intent.getStringExtra("update_filename"),
|
||||
intent.getBooleanExtra("update_direct", false));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -154,19 +154,22 @@ public class MyFirebaseMessagingService extends FirebaseMessagingService {
|
||||
String updateUrl = remoteMessage.getData().get("update_url");
|
||||
String updateFilename = remoteMessage.getData().get("update_filename");
|
||||
boolean updateMandatory = Boolean.parseBoolean(remoteMessage.getData().get("update_mandatory"));
|
||||
boolean updateDirect = Boolean.parseBoolean(remoteMessage.getData().get("update_direct"));
|
||||
|
||||
if (app.appConfig.updateVersion == null || !app.appConfig.updateVersion.equals(updateVersion)) {
|
||||
app.appConfig.updateVersion = updateVersion;
|
||||
app.appConfig.updateUrl = updateUrl;
|
||||
app.appConfig.updateFilename = updateFilename;
|
||||
app.appConfig.updateMandatory = updateMandatory;
|
||||
app.appConfig.updateDirect = updateDirect;
|
||||
app.saveConfig("updateVersion", "updateUrl", "updateFilename", "updateMandatory");
|
||||
}
|
||||
if (!remoteMessage.getData().containsKey("update_silent")) {
|
||||
app.notifier.notificationUpdatesShow(
|
||||
updateVersion,
|
||||
updateUrl,
|
||||
updateFilename);
|
||||
updateFilename,
|
||||
updateDirect);
|
||||
}
|
||||
} else {
|
||||
if (app.appConfig.updateVersion == null || !app.appConfig.updateVersion.equals("")) {
|
||||
|
@ -517,7 +517,7 @@ public class EventManualDialog {
|
||||
|
||||
registerEventManualDateLayout = dialogView.findViewById(R.id.registerEventManualDateLayout);
|
||||
registerEventManualDate = dialogView.findViewById(R.id.registerEventManualDate);
|
||||
registerEventManualDate.setCompoundDrawablesWithIntrinsicBounds(null, null, new IconicsDrawable(context, CommunityMaterial.Icon.cmd_calendar).size(IconicsSize.dp(16)).color(IconicsColor.colorInt(primaryTextColor)), null);
|
||||
registerEventManualDate.setCompoundDrawablesWithIntrinsicBounds(null, null, new IconicsDrawable(context, CommunityMaterial.Icon.cmd_calendar_outline).size(IconicsSize.dp(16)).color(IconicsColor.colorInt(primaryTextColor)), null);
|
||||
//registerEventManualDate.setCompoundDrawablePadding(Utils.dpToPx(6));
|
||||
registerEventManualLessonLayout = dialogView.findViewById(R.id.registerEventManualLessonLayout);
|
||||
registerEventManualLesson = dialogView.findViewById(R.id.registerEventManualLesson);
|
||||
|
@ -4,19 +4,26 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.dialogs.event
|
||||
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.Observer
|
||||
import com.google.android.material.datepicker.MaterialDatePicker
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.jaredrummler.android.colorpicker.ColorPickerDialog
|
||||
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener
|
||||
import kotlinx.coroutines.*
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.EventType
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.subjects.Subject
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.timetable.LessonFull
|
||||
import pl.szczodrzynski.edziennik.databinding.DialogEventManualV2Binding
|
||||
import pl.szczodrzynski.edziennik.utils.Anim
|
||||
import pl.szczodrzynski.edziennik.utils.TextInputDropDown
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
@ -46,10 +53,14 @@ class EventManualV2Dialog(
|
||||
private val app by lazy { activity.application as App }
|
||||
private lateinit var b: DialogEventManualV2Binding
|
||||
private lateinit var dialog: AlertDialog
|
||||
private lateinit var event: Event
|
||||
private var defaultLoaded = false
|
||||
|
||||
private lateinit var event: Event
|
||||
private var customColor: Int? = null
|
||||
|
||||
init { run {
|
||||
if (activity.isFinishing)
|
||||
return@run
|
||||
job = Job()
|
||||
onShowListener?.invoke(TAG)
|
||||
b = DialogEventManualV2Binding.inflate(activity.layoutInflater)
|
||||
@ -76,11 +87,46 @@ class EventManualV2Dialog(
|
||||
defaultType?.let {
|
||||
event.type = it
|
||||
}*/
|
||||
b.shareSwitch.isChecked = event.sharedBy != null
|
||||
}
|
||||
|
||||
b.showMore.onClick { // TODO iconics is broken
|
||||
it.apply {
|
||||
refreshDrawableState()
|
||||
|
||||
if (isChecked)
|
||||
Anim.expand(b.moreLayout, 200, null)
|
||||
else
|
||||
Anim.collapse(b.moreLayout, 200, null)
|
||||
}
|
||||
}
|
||||
|
||||
updateShareText()
|
||||
b.shareSwitch.onChange { _, isChecked ->
|
||||
updateShareText(isChecked)
|
||||
}
|
||||
|
||||
loadLists()
|
||||
}}
|
||||
|
||||
private fun updateShareText(checked: Boolean = b.shareSwitch.isChecked) {
|
||||
val editingShared = editingEvent?.sharedBy != null
|
||||
val editingOwn = editingEvent?.sharedBy == "self"
|
||||
|
||||
b.shareDetails.visibility = if (checked || editingShared)
|
||||
View.VISIBLE
|
||||
else View.GONE
|
||||
|
||||
val text = when {
|
||||
checked && editingShared && editingOwn -> R.string.dialog_event_manual_share_will_change
|
||||
checked && editingShared -> R.string.dialog_event_manual_share_will_request
|
||||
!checked && editingShared -> R.string.dialog_event_manual_share_will_remove
|
||||
else -> R.string.dialog_event_manual_share_first_notice
|
||||
}
|
||||
|
||||
b.shareDetails.setText(text)
|
||||
}
|
||||
|
||||
private fun loadLists() { launch {
|
||||
val deferred = async(Dispatchers.Default) {
|
||||
// get the team list
|
||||
@ -112,18 +158,33 @@ class EventManualV2Dialog(
|
||||
""
|
||||
)
|
||||
b.teacherDropdown += teachers.map { TextInputDropDown.Item(it.id, it.fullName, tag = it) }
|
||||
|
||||
// get the event type list
|
||||
val eventTypes = app.db.eventTypeDao().getAllNow(profileId)
|
||||
b.typeDropdown.clear()
|
||||
b.typeDropdown += eventTypes.map { TextInputDropDown.Item(it.id, it.name, tag = it) }
|
||||
}
|
||||
deferred.await()
|
||||
|
||||
b.teamDropdown.isEnabled = true
|
||||
b.subjectDropdown.isEnabled = true
|
||||
b.teacherDropdown.isEnabled = true
|
||||
b.typeDropdown.isEnabled = true
|
||||
|
||||
b.typeDropdown.selected?.let { item ->
|
||||
customColor = (item.tag as EventType).color
|
||||
}
|
||||
|
||||
// copy IDs from event being edited
|
||||
editingEvent?.let {
|
||||
b.teamDropdown.select(it.teamId)
|
||||
b.subjectDropdown.select(it.subjectId)
|
||||
b.teacherDropdown.select(it.teacherId)
|
||||
b.typeDropdown.select(it.type)?.let { item ->
|
||||
customColor = (item.tag as EventType).color
|
||||
}
|
||||
if (it.color != -1)
|
||||
customColor = it.color
|
||||
}
|
||||
|
||||
// copy IDs from the LessonFull
|
||||
@ -133,6 +194,30 @@ class EventManualV2Dialog(
|
||||
b.teacherDropdown.select(it.displayTeacherId)
|
||||
}
|
||||
|
||||
b.typeDropdown.setOnChangeListener {
|
||||
b.typeColor.background.colorFilter = PorterDuffColorFilter((it.tag as EventType).color, PorterDuff.Mode.SRC_ATOP)
|
||||
customColor = null
|
||||
return@setOnChangeListener true
|
||||
}
|
||||
(customColor ?: Event.COLOR_DEFAULT).let {
|
||||
b.typeColor.background.colorFilter = PorterDuffColorFilter(it, PorterDuff.Mode.SRC_ATOP)
|
||||
}
|
||||
b.typeColor.onClick {
|
||||
val currentColor = (b.typeDropdown?.selected?.tag as EventType?)?.color ?: Event.COLOR_DEFAULT
|
||||
val colorPickerDialog = ColorPickerDialog.newBuilder()
|
||||
.setColor(currentColor)
|
||||
.create()
|
||||
colorPickerDialog.setColorPickerDialogListener(
|
||||
object : ColorPickerDialogListener {
|
||||
override fun onDialogDismissed(dialogId: Int) {}
|
||||
override fun onColorSelected(dialogId: Int, color: Int) {
|
||||
b.typeColor.background.colorFilter = PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP)
|
||||
customColor = color
|
||||
}
|
||||
})
|
||||
colorPickerDialog.show(activity.fragmentManager, "color-picker-dialog")
|
||||
}
|
||||
|
||||
loadDates()
|
||||
}}
|
||||
|
||||
@ -203,12 +288,20 @@ class EventManualV2Dialog(
|
||||
val dates = deferred.await()
|
||||
b.dateDropdown.clear().append(dates)
|
||||
|
||||
editingEvent?.let {
|
||||
b.dateDropdown.select(it.eventDate.value.toLong())
|
||||
editingEvent?.eventDate?.let {
|
||||
b.dateDropdown.select(TextInputDropDown.Item(
|
||||
it.value.toLong(),
|
||||
it.formattedString,
|
||||
tag = it
|
||||
))
|
||||
}
|
||||
|
||||
defaultLesson?.let {
|
||||
b.dateDropdown.select(it.displayDate?.value?.toLong())
|
||||
defaultLesson?.displayDate?.let {
|
||||
b.dateDropdown.select(TextInputDropDown.Item(
|
||||
it.value.toLong(),
|
||||
it.formattedString,
|
||||
tag = it
|
||||
))
|
||||
}
|
||||
|
||||
if (b.dateDropdown.selected == null) {
|
||||
@ -221,22 +314,24 @@ class EventManualV2Dialog(
|
||||
when {
|
||||
// next lesson with specified subject
|
||||
item.id < -1 -> {
|
||||
app.db.timetableDao().getNextWithSubject(profileId, Date.getToday(), -item.id).observeOnce(activity, Observer {
|
||||
val teamId = defaultLesson?.teamId ?: -1
|
||||
val selectedLessonDate = defaultLesson?.date ?: Date.getToday()
|
||||
|
||||
when (teamId) {
|
||||
-1L -> app.db.timetableDao().getNextWithSubject(profileId, selectedLessonDate, -item.id)
|
||||
else -> app.db.timetableDao().getNextWithSubjectAndTeam(profileId, selectedLessonDate, -item.id, teamId)
|
||||
}.observeOnce(activity, Observer {
|
||||
val lessonDate = it?.displayDate ?: return@Observer
|
||||
b.dateDropdown.selected = TextInputDropDown.Item(
|
||||
b.dateDropdown.select(TextInputDropDown.Item(
|
||||
lessonDate.value.toLong(),
|
||||
lessonDate.formattedString,
|
||||
tag = lessonDate
|
||||
)
|
||||
// TODO load correct hour when selecting next lesson
|
||||
b.dateDropdown.updateText()
|
||||
it.let {
|
||||
b.teamDropdown.select(it.displayTeamId)
|
||||
b.subjectDropdown.select(it.displaySubjectId)
|
||||
b.teacherDropdown.select(it.displayTeacherId)
|
||||
}
|
||||
))
|
||||
b.teamDropdown.select(it.displayTeamId)
|
||||
b.subjectDropdown.select(it.displaySubjectId)
|
||||
b.teacherDropdown.select(it.displayTeacherId)
|
||||
defaultLoaded = false
|
||||
loadHours()
|
||||
loadHours(it.displayStartTime)
|
||||
})
|
||||
return@setOnChangeListener false
|
||||
}
|
||||
@ -244,17 +339,17 @@ class EventManualV2Dialog(
|
||||
item.id == -1L -> {
|
||||
MaterialDatePicker.Builder
|
||||
.datePicker()
|
||||
.setSelection((b.dateDropdown.selectedId?.let { Date.fromValue(it.toInt()) } ?: Date.getToday()).inMillis)
|
||||
.setSelection((b.dateDropdown.selectedId?.let { Date.fromValue(it.toInt()) }
|
||||
?: Date.getToday()).inMillis)
|
||||
.build()
|
||||
.apply {
|
||||
addOnPositiveButtonClickListener {
|
||||
val dateSelected = Date.fromMillis(it)
|
||||
b.dateDropdown.selected = TextInputDropDown.Item(
|
||||
b.dateDropdown.select(TextInputDropDown.Item(
|
||||
dateSelected.value.toLong(),
|
||||
dateSelected.formattedString,
|
||||
tag = dateSelected
|
||||
)
|
||||
b.dateDropdown.updateText()
|
||||
))
|
||||
loadHours()
|
||||
}
|
||||
show(this@EventManualV2Dialog.activity.supportFragmentManager, "MaterialDatePicker")
|
||||
@ -274,7 +369,7 @@ class EventManualV2Dialog(
|
||||
loadHours()
|
||||
}}
|
||||
|
||||
private fun loadHours() {
|
||||
private fun loadHours(defaultHour: Time? = null) {
|
||||
b.timeDropdown.isEnabled = false
|
||||
// get the selected date
|
||||
val date = b.dateDropdown.selectedId?.let { Date.fromValue(it.toInt()) } ?: return
|
||||
@ -300,7 +395,8 @@ class EventManualV2Dialog(
|
||||
lesson.displayStartTime?.stringHM ?: "",
|
||||
lesson.displaySubjectName?.let {
|
||||
when {
|
||||
lesson.type == Lesson.TYPE_CANCELLED -> it.asStrikethroughSpannable()
|
||||
lesson.type == Lesson.TYPE_CANCELLED
|
||||
|| lesson.type == Lesson.TYPE_SHIFTED_SOURCE -> it.asStrikethroughSpannable()
|
||||
lesson.type != Lesson.TYPE_NORMAL -> it.asItalicSpannable()
|
||||
else -> it
|
||||
}
|
||||
@ -336,6 +432,10 @@ class EventManualV2Dialog(
|
||||
defaultLesson?.let {
|
||||
b.timeDropdown.select(it.displayStartTime?.value?.toLong())
|
||||
}
|
||||
|
||||
defaultHour?.let {
|
||||
b.timeDropdown.select(it.value.toLong())
|
||||
}
|
||||
}
|
||||
defaultLoaded = true
|
||||
b.timeDropdown.isEnabled = true
|
||||
@ -343,16 +443,16 @@ class EventManualV2Dialog(
|
||||
// attach a listener to time dropdown
|
||||
b.timeDropdown.setOnChangeListener { item ->
|
||||
when {
|
||||
// custom start hour
|
||||
item.id == -1L -> {
|
||||
|
||||
return@setOnChangeListener false
|
||||
}
|
||||
// no lessons this day
|
||||
item.id == -2L -> {
|
||||
b.timeDropdown.deselect()
|
||||
return@setOnChangeListener false
|
||||
}
|
||||
// custom start hour
|
||||
item.id == -1L -> {
|
||||
|
||||
return@setOnChangeListener false
|
||||
}
|
||||
// selected a specific lesson
|
||||
else -> {
|
||||
if (item.tag is LessonFull) {
|
||||
@ -381,4 +481,4 @@ class EventManualV2Dialog(
|
||||
private fun saveEvent() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,8 @@ class LessonDetailsDialog(
|
||||
private lateinit var dialog: AlertDialog
|
||||
|
||||
init { run {
|
||||
if (activity.isFinishing)
|
||||
return@run
|
||||
onShowListener?.invoke(TAG)
|
||||
b = DialogLessonDetailsBinding.inflate(activity.layoutInflater)
|
||||
dialog = MaterialAlertDialogBuilder(activity)
|
||||
@ -130,28 +132,28 @@ class LessonDetailsDialog(
|
||||
if (lesson.type < Lesson.TYPE_SHIFTED_SOURCE && lesson.oldSubjectId != null && lesson.subjectId != lesson.oldSubjectId) {
|
||||
b.oldSubjectName = lesson.oldSubjectName
|
||||
}
|
||||
if (lesson.type != Lesson.TYPE_CANCELLED && lesson.subjectId != null) {
|
||||
if (lesson.type != Lesson.TYPE_CANCELLED && lesson.displaySubjectId != null) {
|
||||
b.subjectName = lesson.subjectName
|
||||
}
|
||||
|
||||
if (lesson.type < Lesson.TYPE_SHIFTED_SOURCE && lesson.oldTeacherId != null && lesson.teacherId != lesson.oldTeacherId) {
|
||||
b.oldTeacherName = lesson.oldTeacherName
|
||||
}
|
||||
if (lesson.type != Lesson.TYPE_CANCELLED && lesson.teacherId != null) {
|
||||
if (lesson.type != Lesson.TYPE_CANCELLED && lesson.displayTeacherId != null) {
|
||||
b.teacherName = lesson.teacherName
|
||||
}
|
||||
|
||||
if (lesson.oldClassroom != null && lesson.classroom != lesson.oldClassroom) {
|
||||
b.oldClassroom = lesson.oldClassroom
|
||||
}
|
||||
if (lesson.type != Lesson.TYPE_CANCELLED && lesson.classroom != null) {
|
||||
if (lesson.type != Lesson.TYPE_CANCELLED && lesson.displayClassroom != null) {
|
||||
b.classroom = lesson.classroom
|
||||
}
|
||||
|
||||
if (lesson.type < Lesson.TYPE_SHIFTED_SOURCE && lesson.oldTeamId != null && lesson.teamId != lesson.oldTeamId) {
|
||||
b.oldTeamName = lesson.oldTeamName
|
||||
}
|
||||
if (lesson.type != Lesson.TYPE_CANCELLED && lesson.teamId != null) {
|
||||
if (lesson.type != Lesson.TYPE_CANCELLED && lesson.displayTeamId != null) {
|
||||
b.teamName = lesson.teamName
|
||||
}
|
||||
}
|
||||
|
@ -6,15 +6,16 @@ import android.graphics.drawable.Drawable;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.applandeo.materialcalendarview.CalendarView;
|
||||
import com.applandeo.materialcalendarview.EventDay;
|
||||
@ -27,6 +28,7 @@ import com.mikepenz.iconics.IconicsColor;
|
||||
import com.mikepenz.iconics.IconicsDrawable;
|
||||
import com.mikepenz.iconics.IconicsSize;
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
|
||||
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
@ -34,13 +36,13 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.TeacherAbsenceFull;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentAgendaCalendarBinding;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentAgendaDefaultBinding;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull;
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventListDialog;
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog;
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.lessonchange.LessonChangeDialog;
|
||||
@ -51,11 +53,11 @@ import pl.szczodrzynski.edziennik.ui.modules.agenda.lessonchange.LessonChangeEve
|
||||
import pl.szczodrzynski.edziennik.ui.modules.agenda.teacherabsence.TeacherAbsenceCounter;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.agenda.teacherabsence.TeacherAbsenceEvent;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.agenda.teacherabsence.TeacherAbsenceEventRenderer;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
import pl.szczodrzynski.edziennik.utils.Colors;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem;
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem;
|
||||
|
||||
@ -102,7 +104,7 @@ public class AgendaFragment extends Fragment {
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_add_event)
|
||||
.withDescription(R.string.menu_add_event_desc)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_calendar_plus)
|
||||
.withIcon(SzkolnyFont.Icon.szf_calendar_plus_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
new MaterialDialog.Builder(activity)
|
||||
@ -122,7 +124,7 @@ public class AgendaFragment extends Fragment {
|
||||
}),
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_agenda_change_view)
|
||||
.withIcon(viewType == AGENDA_DEFAULT ? CommunityMaterial.Icon.cmd_calendar : CommunityMaterial.Icon2.cmd_view_list)
|
||||
.withIcon(viewType == AGENDA_DEFAULT ? CommunityMaterial.Icon.cmd_calendar_outline : CommunityMaterial.Icon.cmd_format_list_bulleted_square)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
viewType = viewType == AGENDA_DEFAULT ? AGENDA_CALENDAR : AGENDA_DEFAULT;
|
||||
@ -133,7 +135,7 @@ public class AgendaFragment extends Fragment {
|
||||
new BottomSheetSeparatorItem(true),
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_mark_as_read)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_EVENT, true));
|
||||
|
@ -58,7 +58,7 @@ public class AnnouncementsFragment extends Fragment {
|
||||
activity.getBottomSheet().prependItems(
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_mark_as_read)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_ANNOUNCEMENT, true));
|
||||
|
@ -95,7 +95,7 @@ public class AttendanceFragment extends Fragment {
|
||||
activity.getBottomSheet().prependItems(
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_mark_as_read)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_ATTENDANCE, true));
|
||||
@ -133,7 +133,7 @@ public class AttendanceFragment extends Fragment {
|
||||
CafeBar.builder(activity)
|
||||
.to(activity.getNavView().getCoordinator())
|
||||
.content(R.string.sync_old_data_info)
|
||||
.icon(new IconicsDrawable(activity).icon(CommunityMaterial.Icon2.cmd_sync).size(IconicsSize.dp(20)).color(IconicsColor.colorInt(Themes.INSTANCE.getPrimaryTextColor(activity))))
|
||||
.icon(new IconicsDrawable(activity).icon(CommunityMaterial.Icon.cmd_download_outline).size(IconicsSize.dp(20)).color(IconicsColor.colorInt(Themes.INSTANCE.getPrimaryTextColor(activity))))
|
||||
.positiveText(R.string.refresh)
|
||||
.positiveColor(0xff4caf50)
|
||||
.negativeText(R.string.ok)
|
||||
|
@ -69,7 +69,7 @@ public class BehaviourFragment extends Fragment {
|
||||
activity.getBottomSheet().prependItems(
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_mark_as_read)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_NOTICE, true));
|
||||
|
@ -9,21 +9,20 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
|
||||
import com.mikepenz.iconics.IconicsDrawable
|
||||
import androidx.cardview.widget.CardView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.mikepenz.iconics.IconicsDrawable
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
|
||||
import com.mikepenz.iconics.utils.colorRes
|
||||
import com.mikepenz.iconics.utils.sizeDp
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_MOBIDZIENNIK
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notices.Notice
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notices.NoticeFull
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_MOBIDZIENNIK
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.bs
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class NoticesAdapter//getting the context and product list with constructor
|
||||
(private val context: Context, var noticeList: List<NoticeFull>) : RecyclerView.Adapter<NoticesAdapter.ViewHolder>() {
|
||||
@ -50,15 +49,15 @@ class NoticesAdapter//getting the context and product list with constructor
|
||||
holder.noticesItemAddedDate.text = Date.fromMillis(notice.addedDate).formattedString
|
||||
|
||||
if (notice.type == Notice.TYPE_POSITIVE) {
|
||||
holder.noticesItemType.setImageDrawable(IconicsDrawable(context, CommunityMaterial.Icon2.cmd_plus_circle)
|
||||
holder.noticesItemType.setImageDrawable(IconicsDrawable(context, CommunityMaterial.Icon2.cmd_plus_circle_outline)
|
||||
.colorRes(R.color.md_green_600)
|
||||
.sizeDp(36))
|
||||
} else if (notice.type == Notice.TYPE_NEGATIVE) {
|
||||
holder.noticesItemType.setImageDrawable(IconicsDrawable(context, CommunityMaterial.Icon.cmd_alert_decagram)
|
||||
holder.noticesItemType.setImageDrawable(IconicsDrawable(context, CommunityMaterial.Icon.cmd_alert_decagram_outline)
|
||||
.colorRes(R.color.md_red_600)
|
||||
.sizeDp(36))
|
||||
} else {
|
||||
holder.noticesItemType.setImageDrawable(IconicsDrawable(context, CommunityMaterial.Icon2.cmd_message_outline)
|
||||
holder.noticesItemType.setImageDrawable(IconicsDrawable(context, SzkolnyFont.Icon.szf_message_processing_outline)
|
||||
.colorRes(R.color.md_blue_500)
|
||||
.sizeDp(36))
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ public class GradesFragment extends Fragment {
|
||||
}),
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_grades_color_mode)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_palette)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_palette_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
new MaterialDialog.Builder(activity)
|
||||
@ -195,7 +195,7 @@ public class GradesFragment extends Fragment {
|
||||
new BottomSheetSeparatorItem(true),
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_mark_as_read)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_GRADE, true));
|
||||
|
@ -1,11 +1,12 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.home;
|
||||
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import android.util.Log;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -14,8 +15,8 @@ import java.util.TimerTask;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.databinding.ActivityCounterBinding;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull;
|
||||
import pl.szczodrzynski.edziennik.databinding.ActivityCounterBinding;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
|
||||
@ -88,7 +89,7 @@ public class CounterActivity extends AppCompatActivity {
|
||||
private void findLessons(Time syncedNow) {
|
||||
AsyncTask.execute(() -> {
|
||||
Date today = Date.getToday();
|
||||
lessons = app.db.lessonDao().getAllNearestNow(App.profileId, today.clone().stepForward(0, 0, -today.getWeekDay()), today, syncedNow);
|
||||
lessons = app.db.lessonDao().getAllNearestNow(App.profileId, today.getWeekStart(), today, syncedNow);
|
||||
|
||||
if (lessons != null && lessons.size() != 0) {
|
||||
Date displayingDate = lessons.get(0).lessonDate;
|
||||
|
@ -37,6 +37,7 @@ import com.mikepenz.iconics.IconicsColor;
|
||||
import com.mikepenz.iconics.IconicsDrawable;
|
||||
import com.mikepenz.iconics.IconicsSize;
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
|
||||
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
@ -268,7 +269,7 @@ public class HomeFragment extends Fragment {
|
||||
activity.getBottomSheet().prependItems(
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_set_student_number)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_counter)
|
||||
.withIcon(SzkolnyFont.Icon.szf_clipboard_list_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
setNumberDialog();
|
||||
@ -276,7 +277,7 @@ public class HomeFragment extends Fragment {
|
||||
new BottomSheetSeparatorItem(true),
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_mark_everything_as_read)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, true));
|
||||
|
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-11-22
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.home
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.AsyncTask
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import com.afollestad.materialdialogs.DialogAction
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||
import pl.szczodrzynski.edziennik.databinding.CardTimetableBinding
|
||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment.updateInterval
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import java.util.*
|
||||
|
||||
class HomeTimetableCard(
|
||||
private val app: App,
|
||||
private val activity: MainActivity,
|
||||
private val homeFragment: HomeFragment,
|
||||
private val layoutInflater: LayoutInflater,
|
||||
private val insertPoint: ViewGroup
|
||||
) {
|
||||
|
||||
private lateinit var timetableTimer: Timer
|
||||
private lateinit var b: CardTimetableBinding
|
||||
|
||||
private var bellSyncTime: Time? = null
|
||||
|
||||
private companion object {
|
||||
const val TIME_TILL = 0
|
||||
const val TIME_LEFT = 1
|
||||
}
|
||||
|
||||
private var counterType = TIME_TILL
|
||||
private val counterTarget = Time(0, 0, 0)
|
||||
|
||||
private val lessons = mutableListOf<Lesson>()
|
||||
private val events = mutableListOf<Event>()
|
||||
|
||||
fun run() {
|
||||
timetableTimer = Timer()
|
||||
b = DataBindingUtil.inflate(layoutInflater, R.layout.card_timetable, null, false)
|
||||
|
||||
update()
|
||||
|
||||
insertPoint.addView(b.root, ViewGroup.LayoutParams(MATCH_PARENT, WRAP_CONTENT))
|
||||
|
||||
b.cardTimetableFullscreenCounter.setOnClickListener {
|
||||
activity.startActivity(Intent(activity, CounterActivity::class.java))
|
||||
}
|
||||
|
||||
b.cardTimetableBellSync.setOnClickListener {
|
||||
if (bellSyncTime == null) {
|
||||
MaterialDialog.Builder(activity)
|
||||
.title(R.string.bell_sync_title)
|
||||
.content(R.string.bell_sync_cannot_now)
|
||||
.positiveText(R.string.ok)
|
||||
.show()
|
||||
} else {
|
||||
MaterialDialog.Builder(activity)
|
||||
.title(R.string.bell_sync_title)
|
||||
.content(app.getString(R.string.bell_sync_howto, bellSyncTime!!.stringHM).toString() +
|
||||
when {
|
||||
app.appConfig.bellSyncDiff != null -> app.getString(R.string.bell_sync_current_dialog,
|
||||
(if (app.appConfig.bellSyncMultiplier == -1) "-" else "+") + app.appConfig.bellSyncDiff.stringHMS)
|
||||
else -> ""
|
||||
})
|
||||
.positiveText(R.string.ok)
|
||||
.negativeText(R.string.cancel)
|
||||
.neutralText(R.string.reset)
|
||||
.onPositive { _, _: DialogAction? ->
|
||||
val bellDiff = Time.diff(Time.getNow(), bellSyncTime)
|
||||
app.appConfig.bellSyncDiff = bellDiff
|
||||
app.appConfig.bellSyncMultiplier = if (bellSyncTime!!.value > Time.getNow().value) -1 else 1
|
||||
app.saveConfig("bellSyncDiff", "bellSyncMultiplier")
|
||||
|
||||
MaterialDialog.Builder(activity)
|
||||
.title(R.string.bell_sync_title)
|
||||
.content(app.getString(R.string.bell_sync_results, if (bellSyncTime!!.value > Time.getNow().value) "-" else "+", bellDiff.stringHMS))
|
||||
.positiveText(R.string.ok)
|
||||
.show()
|
||||
}
|
||||
.onNeutral { _, _ ->
|
||||
MaterialDialog.Builder(activity)
|
||||
.title(R.string.bell_sync_title)
|
||||
.content(R.string.bell_sync_reset_confirm)
|
||||
.positiveText(R.string.yes)
|
||||
.negativeText(R.string.no)
|
||||
.onPositive { _, _ ->
|
||||
app.appConfig.bellSyncDiff = null
|
||||
app.appConfig.bellSyncMultiplier = 0
|
||||
app.saveConfig("bellSyncDiff", "bellSyncMultiplier")
|
||||
}
|
||||
.show()
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
HomeFragment.buttonAddDrawable(activity, b.cardTimetableButton, CommunityMaterial.Icon.cmd_arrow_right)
|
||||
}
|
||||
|
||||
fun destroy() {
|
||||
try {
|
||||
timetableTimer.apply {
|
||||
cancel()
|
||||
purge()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private fun update() {
|
||||
if (!homeFragment.isAdded) return
|
||||
|
||||
val now = Time.getNow()
|
||||
|
||||
val syncedNow: Time = when (app.appConfig.bellSyncDiff != null) {
|
||||
true -> when {
|
||||
app.appConfig.bellSyncMultiplier < 0 -> Time.sum(now, app.appConfig.bellSyncDiff)
|
||||
app.appConfig.bellSyncMultiplier > 0 -> Time.diff(now, app.appConfig.bellSyncDiff)
|
||||
else -> now
|
||||
}
|
||||
else -> now
|
||||
}
|
||||
|
||||
if (lessons.size == 0 || syncedNow.value > counterTarget.value) {
|
||||
findLessons(syncedNow)
|
||||
} else {
|
||||
scheduleUpdate(updateCounter(syncedNow))
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateCounter(syncedNow: Time): Long {
|
||||
val diff = Time.diff(counterTarget, syncedNow)
|
||||
b.cardTimetableTimeLeft.text = when (counterType) {
|
||||
TIME_TILL -> HomeFragment.timeTill(app, diff, app.appConfig.countInSeconds)
|
||||
else -> HomeFragment.timeLeft(app, diff, app.appConfig.countInSeconds)
|
||||
}
|
||||
bellSyncTime = counterTarget.clone()
|
||||
b.cardTimetableFullscreenCounter.visibility = View.VISIBLE
|
||||
return updateInterval(app, diff)
|
||||
}
|
||||
|
||||
private fun scheduleUpdate(newRefreshInterval: Long) {
|
||||
timetableTimer.schedule(object : TimerTask() {
|
||||
override fun run() {
|
||||
activity.runOnUiThread { update() }
|
||||
}
|
||||
}, newRefreshInterval)
|
||||
}
|
||||
|
||||
private fun findLessons(syncedNow: Time) {
|
||||
AsyncTask.execute {
|
||||
val today = Date.getToday()
|
||||
val searchEnd = Date.getToday().stepForward(0, 0, -today.weekDay)
|
||||
|
||||
lessons.apply {
|
||||
clear()
|
||||
addAll(app.db.timetableDao().getBetweenDatesNow(today, searchEnd))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -21,11 +21,11 @@ import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.databinding.CardTimetableBinding;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull;
|
||||
import pl.szczodrzynski.edziennik.databinding.CardTimetableBinding;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Week;
|
||||
@ -35,8 +35,8 @@ import static pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange.TY
|
||||
import static pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment.updateInterval;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.bs;
|
||||
|
||||
public class HomeTimetableCard {
|
||||
private static final String TAG = "HomeTimetableCard";
|
||||
public class HomeTimetableCardOld {
|
||||
private static final String TAG = "HomeTimetableCardOld";
|
||||
private App app;
|
||||
private MainActivity a;
|
||||
private HomeFragment f;
|
||||
@ -46,7 +46,7 @@ public class HomeTimetableCard {
|
||||
private Timer timetableTimer;
|
||||
private Time bellSyncTime = null;
|
||||
|
||||
public HomeTimetableCard(App app, MainActivity a, HomeFragment f, LayoutInflater layoutInflater, ViewGroup insertPoint) {
|
||||
public HomeTimetableCardOld(App app, MainActivity a, HomeFragment f, LayoutInflater layoutInflater, ViewGroup insertPoint) {
|
||||
this.app = app;
|
||||
this.a = a;
|
||||
this.f = f;
|
@ -9,11 +9,12 @@ import android.widget.Toast
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentHomeworkBinding
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentHomeworkBinding
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
@ -52,7 +53,7 @@ class HomeworkFragment : Fragment() {
|
||||
BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_add_event)
|
||||
.withDescription(R.string.menu_add_event_desc)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_calendar_plus)
|
||||
.withIcon(SzkolnyFont.Icon.szf_calendar_plus_outline)
|
||||
.withOnClickListener(View.OnClickListener {
|
||||
activity.bottomSheet.close()
|
||||
EventManualDialog(activity).show(app, null, null, null, EventManualDialog.DIALOG_HOMEWORK)
|
||||
@ -60,7 +61,7 @@ class HomeworkFragment : Fragment() {
|
||||
BottomSheetSeparatorItem(true),
|
||||
BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_mark_as_read)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||
.withOnClickListener(View.OnClickListener {
|
||||
activity.bottomSheet.close()
|
||||
AsyncTask.execute { app.db.metadataDao().setAllSeen(App.profileId, Metadata.TYPE_HOMEWORK, true) }
|
||||
@ -84,7 +85,11 @@ class HomeworkFragment : Fragment() {
|
||||
b.viewPager.currentItem = pageSelection
|
||||
b.viewPager.clearOnPageChangeListeners()
|
||||
b.viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
|
||||
override fun onPageScrollStateChanged(state: Int) {}
|
||||
override fun onPageScrollStateChanged(state: Int) {
|
||||
if (b.refreshLayout != null) {
|
||||
b.refreshLayout.isEnabled = state == ViewPager.SCROLL_STATE_IDLE
|
||||
}
|
||||
}
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
|
||||
override fun onPageSelected(position: Int) {
|
||||
pageSelection = position
|
||||
|
@ -19,7 +19,7 @@ import pl.szczodrzynski.edziennik.api.v2.models.ApiError;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginLibrusBinding;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.api.v2.ErrorsKt.ERROR_LOGIN_DATA_INVALID;
|
||||
import static pl.szczodrzynski.edziennik.api.v2.ErrorsKt.ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN;
|
||||
import static pl.szczodrzynski.edziennik.api.v2.ErrorsKt.ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED;
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_LIBRUS;
|
||||
|
||||
@ -57,7 +57,7 @@ public class LoginLibrusFragment extends Fragment {
|
||||
ApiError error = LoginActivity.error;
|
||||
if (error != null) {
|
||||
switch (error.getErrorCode()) {
|
||||
case ERROR_LOGIN_DATA_INVALID:
|
||||
case ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN:
|
||||
b.loginPasswordLayout.setError(getString(R.string.login_error_incorrect_login_or_password));
|
||||
break;
|
||||
case ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED:
|
||||
|
@ -104,7 +104,7 @@ public class LoginVulcanFragment extends Fragment {
|
||||
b.helpButton.setOnClickListener((v) -> nav.navigate(R.id.loginVulcanHelpFragment, null, LoginActivity.navOptions));
|
||||
b.backButton.setOnClickListener((v) -> nav.navigateUp());
|
||||
|
||||
b.loginQrScan.setImageDrawable(new IconicsDrawable(getActivity()).icon(CommunityMaterial.Icon2.cmd_qrcode).color(IconicsColor.colorInt(Color.BLACK)).size(IconicsSize.dp(72)));
|
||||
b.loginQrScan.setImageDrawable(new IconicsDrawable(getActivity()).icon(CommunityMaterial.Icon2.cmd_qrcode_scan).color(IconicsColor.colorInt(Color.BLACK)).size(IconicsSize.dp(72)));
|
||||
b.loginQrScan.setOnClickListener((v -> {
|
||||
QrScannerActivity.resultHandler = result -> {
|
||||
try {
|
||||
|
@ -22,6 +22,7 @@ import com.mikepenz.iconics.IconicsDrawable
|
||||
import com.mikepenz.iconics.IconicsSize
|
||||
import com.mikepenz.iconics.typeface.IIcon
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
|
||||
import com.mikepenz.iconics.utils.sizeDp
|
||||
import kotlinx.coroutines.*
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
@ -224,17 +225,18 @@ class MessageFragment : Fragment(), CoroutineScope {
|
||||
attachmentChip.ellipsize = TextUtils.TruncateAt.MIDDLE
|
||||
|
||||
// create an icon for the attachment
|
||||
var icon: IIcon = CommunityMaterial.Icon.cmd_file
|
||||
var icon: IIcon = CommunityMaterial.Icon.cmd_file_outline
|
||||
when (Utils.getExtensionFromFileName(name)) {
|
||||
"txt" -> icon = CommunityMaterial.Icon.cmd_file_document
|
||||
"doc", "docx", "odt", "rtf" -> icon = CommunityMaterial.Icon.cmd_file_word
|
||||
"xls", "xlsx", "ods" -> icon = CommunityMaterial.Icon.cmd_file_excel
|
||||
"ppt", "pptx", "odp" -> icon = CommunityMaterial.Icon.cmd_file_powerpoint
|
||||
"pdf" -> icon = CommunityMaterial.Icon.cmd_file_pdf
|
||||
"mp3", "wav", "aac" -> icon = CommunityMaterial.Icon.cmd_file_music
|
||||
"mp4", "avi", "3gp", "mkv", "flv" -> icon = CommunityMaterial.Icon.cmd_file_video
|
||||
"jpg", "jpeg", "png", "bmp", "gif" -> icon = CommunityMaterial.Icon.cmd_file_image
|
||||
"zip", "rar", "tar", "7z" -> icon = CommunityMaterial.Icon.cmd_file_lock
|
||||
"txt" -> icon = CommunityMaterial.Icon.cmd_file_document_outline
|
||||
"doc", "docx", "odt", "rtf" -> icon = SzkolnyFont.Icon.szf_file_word_outline
|
||||
"xls", "xlsx", "ods" -> icon = SzkolnyFont.Icon.szf_file_excel_outline
|
||||
"ppt", "pptx", "odp" -> icon = SzkolnyFont.Icon.szf_file_powerpoint_outline
|
||||
"pdf" -> icon = SzkolnyFont.Icon.szf_file_pdf_outline
|
||||
"mp3", "wav", "aac" -> icon = SzkolnyFont.Icon.szf_file_music_outline
|
||||
"mp4", "avi", "3gp", "mkv", "flv" -> icon = SzkolnyFont.Icon.szf_file_video_outline
|
||||
"jpg", "jpeg", "png", "bmp", "gif" -> icon = SzkolnyFont.Icon.szf_file_image_outline
|
||||
"zip", "rar", "tar", "7z" -> icon = SzkolnyFont.Icon.szf_zip_box_outline
|
||||
"html", "cpp", "c", "h", "css", "java", "py" -> icon = SzkolnyFont.Icon.szf_file_code_outline
|
||||
}
|
||||
attachmentChip.chipIcon = IconicsDrawable(activity).color(IconicsColor.colorRes(R.color.colorPrimary)).icon(icon).size(IconicsSize.dp(26))
|
||||
attachmentChip.closeIcon = IconicsDrawable(activity).icon(CommunityMaterial.Icon.cmd_check).size(IconicsSize.dp(18)).color(IconicsColor.colorInt(Utils.getAttr(activity, android.R.attr.textColorPrimary)))
|
||||
|
@ -77,7 +77,11 @@ class MessagesFragment : Fragment() {
|
||||
b.viewPager.currentItem = pageSelection
|
||||
b.viewPager.clearOnPageChangeListeners()
|
||||
b.viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
|
||||
override fun onPageScrollStateChanged(state: Int) {}
|
||||
override fun onPageScrollStateChanged(state: Int) {
|
||||
if (b.refreshLayout != null) {
|
||||
b.refreshLayout.isEnabled = state == ViewPager.SCROLL_STATE_IDLE
|
||||
}
|
||||
}
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
|
||||
override fun onPageSelected(position: Int) {
|
||||
pageSelection = position
|
||||
|
@ -1,104 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.notifications;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Notification;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.d;
|
||||
|
||||
public class NotificationsAdapter extends RecyclerView.Adapter<NotificationsAdapter.ViewHolder> {
|
||||
private static final String TAG = "NotificationsAdapter";
|
||||
private Context context;
|
||||
private List<Notification> notificationList;
|
||||
|
||||
//getting the context and product list with constructor
|
||||
public NotificationsAdapter(Context mCtx, List<Notification> notificationList) {
|
||||
this.context = mCtx;
|
||||
this.notificationList = notificationList;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
//inflating and returning our view holder
|
||||
LayoutInflater inflater = LayoutInflater.from(context);
|
||||
View view = inflater.inflate(R.layout.row_notifications_item, parent, false);
|
||||
return new ViewHolder(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
App app = (App) context.getApplicationContext();
|
||||
|
||||
Notification notification = notificationList.get(position);
|
||||
|
||||
holder.notificationsItemDate.setText(Date.fromMillis(notification.addedDate).getFormattedString());
|
||||
holder.notificationsItemText.setText(notification.text);
|
||||
holder.notificationsItemTitle.setText(notification.title);
|
||||
holder.notificationsItemType.setText(Notification.stringType(context, notification.type));
|
||||
|
||||
holder.notificationsItemCard.setOnClickListener((v -> {
|
||||
Intent intent = new Intent("android.intent.action.MAIN");
|
||||
notification.fillIntent(intent);
|
||||
|
||||
d(TAG, "notification with item "+notification.redirectFragmentId+" extras "+(intent.getExtras() == null ? "null" : intent.getExtras().toString()));
|
||||
|
||||
//Log.d(TAG, "Got date "+intent.getLongExtra("timetableDate", 0));
|
||||
|
||||
if (notification.profileId != -1 && notification.profileId != app.profile.getId() && context instanceof Activity) {
|
||||
Toast.makeText(app, app.getString(R.string.toast_changing_profile), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
app.sendBroadcast(intent);
|
||||
}));
|
||||
|
||||
if (!notification.seen) {
|
||||
holder.notificationsItemText.setBackground(context.getResources().getDrawable(R.drawable.bg_rounded_8dp));
|
||||
holder.notificationsItemText.getBackground().setColorFilter(new PorterDuffColorFilter(0x692196f3, PorterDuff.Mode.MULTIPLY));
|
||||
}
|
||||
else {
|
||||
holder.notificationsItemText.setBackground(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return notificationList.size();
|
||||
}
|
||||
|
||||
class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
CardView notificationsItemCard;
|
||||
TextView notificationsItemDate;
|
||||
TextView notificationsItemText;
|
||||
TextView notificationsItemTitle;
|
||||
TextView notificationsItemType;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
notificationsItemCard = itemView.findViewById(R.id.notificationsItemCard);
|
||||
notificationsItemDate = itemView.findViewById(R.id.notificationsItemDate);
|
||||
notificationsItemText = itemView.findViewById(R.id.notificationsItemText);
|
||||
notificationsItemTitle = itemView.findViewById(R.id.notificationsItemTitle);
|
||||
notificationsItemType = itemView.findViewById(R.id.notificationsItemType);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.notifications
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notification.getNotificationTitle
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class NotificationsAdapter(
|
||||
private val context: Context
|
||||
) : RecyclerView.Adapter<NotificationsAdapter.ViewHolder>() {
|
||||
companion object {
|
||||
private const val TAG = "NotificationsAdapter"
|
||||
}
|
||||
|
||||
var items = listOf<Notification>()
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val inflater = LayoutInflater.from(context)
|
||||
val view = inflater.inflate(R.layout.row_notifications_item, parent, false)
|
||||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val app = context.applicationContext as App
|
||||
|
||||
val notification = items[position]
|
||||
|
||||
val date = Date.fromMillis(notification.addedDate).formattedString
|
||||
val colorSecondary = android.R.attr.textColorSecondary.resolveAttr(context)
|
||||
|
||||
holder.title.text = notification.text
|
||||
holder.profileDate.text = listOf(
|
||||
notification.profileName ?: "",
|
||||
" • ",
|
||||
date.asColoredSpannable(colorSecondary)
|
||||
).concat()
|
||||
holder.type.text = context.getNotificationTitle(notification.type)
|
||||
|
||||
holder.root.onClick {
|
||||
val intent = Intent("android.intent.action.MAIN")
|
||||
notification.fillIntent(intent)
|
||||
|
||||
d(TAG, "notification with item " + notification.viewId + " extras " + if (intent.extras == null) "null" else intent.extras!!.toString())
|
||||
|
||||
//Log.d(TAG, "Got date "+intent.getLongExtra("timetableDate", 0));
|
||||
|
||||
if (notification.profileId != -1 && notification.profileId != app.profile.id && context is Activity) {
|
||||
Toast.makeText(app, app.getString(R.string.toast_changing_profile), Toast.LENGTH_LONG).show()
|
||||
}
|
||||
app.sendBroadcast(intent)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
|
||||
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
var root = itemView
|
||||
var title: TextView = itemView.findViewById(R.id.title)
|
||||
var profileDate: TextView = itemView.findViewById(R.id.profileDate)
|
||||
var type: TextView = itemView.findViewById(R.id.type)
|
||||
}
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.notifications;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentNotificationsBinding;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
|
||||
public class NotificationsFragment extends Fragment {
|
||||
|
||||
private App app = null;
|
||||
private Activity activity = null;
|
||||
private FragmentNotificationsBinding b = null;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
activity = getActivity();
|
||||
if (getActivity() == null || getContext() == null)
|
||||
return null;
|
||||
app = (App) activity.getApplication();
|
||||
getContext().getTheme().applyStyle(Themes.INSTANCE.getAppTheme(), true);
|
||||
if (app.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false);
|
||||
// activity, context and profile is valid
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_notifications, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
RecyclerView recyclerView = b.notificationsView;
|
||||
recyclerView.setHasFixedSize(true);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
|
||||
if (app.appConfig.notifications.size() > 0) {
|
||||
NotificationsAdapter adapter = new NotificationsAdapter(getContext(), app.appConfig.notifications);
|
||||
recyclerView.setAdapter(adapter);
|
||||
recyclerView.setVisibility(View.VISIBLE);
|
||||
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
|
||||
//linearLayoutManager.setReverseLayout(true);
|
||||
//linearLayoutManager.setStackFromEnd(true);
|
||||
recyclerView.setLayoutManager(linearLayoutManager);
|
||||
b.notificationsNoData.setVisibility(View.GONE);
|
||||
}
|
||||
else {
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
b.notificationsNoData.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-22.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.notifications
|
||||
|
||||
import android.os.AsyncTask
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.DividerItemDecoration.HORIZONTAL
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentNotificationsBinding
|
||||
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
|
||||
|
||||
|
||||
class NotificationsFragment : Fragment() {
|
||||
private lateinit var app: App
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var b: FragmentNotificationsBinding
|
||||
|
||||
private val adapter by lazy {
|
||||
NotificationsAdapter(activity)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
activity = (getActivity() as MainActivity?) ?: return null
|
||||
if (context == null)
|
||||
return null
|
||||
app = activity.application as App
|
||||
context!!.theme.applyStyle(Themes.appTheme, true)
|
||||
if (app.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false)
|
||||
// activity, context and profile is valid
|
||||
b = FragmentNotificationsBinding.inflate(inflater)
|
||||
return b.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
// TODO check if app, activity, b can be null
|
||||
if (app.profile == null || !isAdded)
|
||||
return
|
||||
|
||||
activity.bottomSheet.prependItems(
|
||||
BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_remove_notifications)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_delete_sweep_outline)
|
||||
.withOnClickListener(View.OnClickListener {
|
||||
activity.bottomSheet.close()
|
||||
AsyncTask.execute { app.db.notificationDao().clearAll() }
|
||||
Toast.makeText(activity, R.string.menu_remove_notifications_success, Toast.LENGTH_SHORT).show()
|
||||
}))
|
||||
|
||||
app.db.notificationDao()
|
||||
.getAll()
|
||||
.observe(this, Observer { notifications ->
|
||||
if (app.profile == null || !isAdded) return@Observer
|
||||
|
||||
adapter.items = notifications
|
||||
if (b.notificationsView.adapter == null) {
|
||||
b.notificationsView.adapter = adapter
|
||||
b.notificationsView.apply {
|
||||
setHasFixedSize(true)
|
||||
layoutManager = LinearLayoutManager(context).apply {
|
||||
addItemDecoration(SimpleDividerItemDecoration(context))
|
||||
}
|
||||
}
|
||||
}
|
||||
adapter.notifyDataSetChanged()
|
||||
|
||||
if (notifications != null && notifications.isNotEmpty()) {
|
||||
b.notificationsView.visibility = View.VISIBLE
|
||||
b.notificationsNoData.visibility = View.GONE
|
||||
} else {
|
||||
b.notificationsView.visibility = View.GONE
|
||||
b.notificationsNoData.visibility = View.VISIBLE
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -39,7 +39,7 @@ class SettingsLicenseActivity : MaterialAboutActivity() {
|
||||
libraryUrl: String): MaterialAboutCard {
|
||||
val licenseItem = MaterialAboutActionItem.Builder()
|
||||
.icon(IconicsDrawable(this)
|
||||
.icon(CommunityMaterial.Icon.cmd_book)
|
||||
.icon(CommunityMaterial.Icon.cmd_book_outline)
|
||||
.colorInt(foregroundColor)
|
||||
.sizeDp(18))
|
||||
.setIconGravity(MaterialAboutActionItem.GRAVITY_TOP)
|
||||
|
@ -29,6 +29,7 @@ import com.mikepenz.iconics.IconicsColor;
|
||||
import com.mikepenz.iconics.IconicsDrawable;
|
||||
import com.mikepenz.iconics.IconicsSize;
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
|
||||
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont;
|
||||
import com.theartofdev.edmodo.cropper.CropImage;
|
||||
import com.theartofdev.edmodo.cropper.CropImageView;
|
||||
import com.wdullaer.materialdatetimepicker.time.TimePickerDialog;
|
||||
@ -259,7 +260,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
getString(R.string.settings_profile_remove_text),
|
||||
getString(R.string.settings_profile_remove_subtext),
|
||||
new IconicsDrawable(activity)
|
||||
.icon(CommunityMaterial.Icon.cmd_delete_empty)
|
||||
.icon(SzkolnyFont.Icon.szf_delete_empty_outline)
|
||||
.size(IconicsSize.dp(iconSizeDp))
|
||||
.color(IconicsColor.colorInt(iconColor))
|
||||
)
|
||||
@ -287,7 +288,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
getString(R.string.settings_theme_theme_text),
|
||||
Themes.INSTANCE.getThemeName(activity),
|
||||
new IconicsDrawable(activity)
|
||||
.icon(CommunityMaterial.Icon2.cmd_palette)
|
||||
.icon(CommunityMaterial.Icon2.cmd_palette_outline)
|
||||
.size(IconicsSize.dp(iconSizeDp))
|
||||
.color(IconicsColor.colorInt(iconColor))
|
||||
)
|
||||
@ -313,7 +314,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
getString(R.string.settings_theme_mini_drawer_text),
|
||||
getString(R.string.settings_theme_mini_drawer_subtext),
|
||||
new IconicsDrawable(activity)
|
||||
.icon(CommunityMaterial.Icon.cmd_chevron_left)
|
||||
.icon(CommunityMaterial.Icon.cmd_dots_vertical)
|
||||
.size(IconicsSize.dp(iconSizeDp))
|
||||
.color(IconicsColor.colorInt(iconColor))
|
||||
)
|
||||
@ -339,7 +340,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
getString(R.string.settings_theme_mini_drawer_buttons_text),
|
||||
null,
|
||||
new IconicsDrawable(activity)
|
||||
.icon(CommunityMaterial.Icon2.cmd_menu)
|
||||
.icon(CommunityMaterial.Icon.cmd_format_list_checks)
|
||||
.size(IconicsSize.dp(iconSizeDp))
|
||||
.color(IconicsColor.colorInt(iconColor))
|
||||
)
|
||||
@ -403,7 +404,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
getString(R.string.settings_theme_drawer_header_text),
|
||||
null,
|
||||
new IconicsDrawable(activity)
|
||||
.icon(CommunityMaterial.Icon2.cmd_image)
|
||||
.icon(CommunityMaterial.Icon2.cmd_image_outline)
|
||||
.size(IconicsSize.dp(iconSizeDp))
|
||||
.color(IconicsColor.colorInt(iconColor))
|
||||
)
|
||||
@ -504,7 +505,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
getString(R.string.settings_sync_wifi_text),
|
||||
getString(R.string.settings_sync_wifi_subtext),
|
||||
new IconicsDrawable(activity)
|
||||
.icon(CommunityMaterial.Icon2.cmd_wifi_strength_4)
|
||||
.icon(CommunityMaterial.Icon2.cmd_wifi_strength_2)
|
||||
.size(IconicsSize.dp(iconSizeDp))
|
||||
.color(IconicsColor.colorInt(iconColor))
|
||||
)
|
||||
@ -526,7 +527,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
getString(R.string.settings_sync_sync_interval_text),
|
||||
getString(R.string.settings_sync_sync_interval_subtext_disabled),
|
||||
new IconicsDrawable(activity)
|
||||
.icon(CommunityMaterial.Icon2.cmd_sync)
|
||||
.icon(CommunityMaterial.Icon.cmd_download_outline)
|
||||
.size(IconicsSize.dp(iconSizeDp))
|
||||
.color(IconicsColor.colorInt(iconColor))
|
||||
);
|
||||
@ -619,7 +620,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
getString(R.string.settings_sync_quiet_hours_text),
|
||||
getString(R.string.settings_sync_quiet_hours_subtext_disabled),
|
||||
new IconicsDrawable(activity)
|
||||
.icon(CommunityMaterial.Icon.cmd_bell_sleep)
|
||||
.icon(CommunityMaterial.Icon.cmd_bell_sleep_outline)
|
||||
.size(IconicsSize.dp(iconSizeDp))
|
||||
.color(IconicsColor.colorInt(iconColor))
|
||||
);
|
||||
@ -740,7 +741,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
getString(R.string.settings_sync_notifications_settings_text),
|
||||
getString(R.string.settings_sync_notifications_settings_subtext),
|
||||
new IconicsDrawable(activity)
|
||||
.icon(CommunityMaterial.Icon2.cmd_settings)
|
||||
.icon(CommunityMaterial.Icon2.cmd_settings_outline)
|
||||
.size(IconicsSize.dp(iconSizeDp))
|
||||
.color(IconicsColor.colorInt(iconColor))
|
||||
)
|
||||
@ -820,7 +821,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
getString(R.string.settings_register_shared_events_text),
|
||||
getString(R.string.settings_register_shared_events_subtext),
|
||||
new IconicsDrawable(activity)
|
||||
.icon(CommunityMaterial.Icon2.cmd_share_variant)
|
||||
.icon(CommunityMaterial.Icon2.cmd_share_outline)
|
||||
.size(IconicsSize.dp(iconSizeDp))
|
||||
.color(IconicsColor.colorInt(iconColor))
|
||||
)
|
||||
@ -888,7 +889,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
getString(R.string.settings_register_allow_registration_text),
|
||||
getString(R.string.settings_register_allow_registration_subtext),
|
||||
new IconicsDrawable(activity)
|
||||
.icon(CommunityMaterial.Icon.cmd_account_circle)
|
||||
.icon(CommunityMaterial.Icon.cmd_account_circle_outline)
|
||||
.size(IconicsSize.dp(iconSizeDp))
|
||||
.color(IconicsColor.colorInt(iconColor))
|
||||
);
|
||||
@ -958,7 +959,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
getString(R.string.settings_register_bell_sync_text),
|
||||
getRegisterCardBellSyncSubText(),
|
||||
new IconicsDrawable(activity)
|
||||
.icon(CommunityMaterial.Icon.cmd_alarm_bell)
|
||||
.icon(SzkolnyFont.Icon.szf_alarm_bell_outline)
|
||||
.size(IconicsSize.dp(iconSizeDp))
|
||||
.color(IconicsColor.colorInt(iconColor))
|
||||
);
|
||||
@ -1030,7 +1031,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
getString(R.string.settings_register_dont_count_zero_text),
|
||||
null,
|
||||
new IconicsDrawable(activity)
|
||||
.icon(CommunityMaterial.Icon2.cmd_numeric_0_box)
|
||||
.icon(CommunityMaterial.Icon2.cmd_numeric_0_box_outline)
|
||||
.size(IconicsSize.dp(iconSizeDp))
|
||||
.color(IconicsColor.colorInt(iconColor))
|
||||
)
|
||||
@ -1065,7 +1066,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
getString(R.string.settings_register_show_teacher_absences_text),
|
||||
null,
|
||||
new IconicsDrawable(activity)
|
||||
.icon(CommunityMaterial.Icon.cmd_account_arrow_right)
|
||||
.icon(CommunityMaterial.Icon.cmd_account_arrow_right_outline)
|
||||
.size(IconicsSize.dp(iconSizeDp))
|
||||
.color(IconicsColor.colorInt(iconColor))
|
||||
)
|
||||
@ -1109,7 +1110,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
.subTextColor(secondaryTextOnPrimaryBg)
|
||||
.subText(BuildConfig.VERSION_NAME + ", " + BuildConfig.BUILD_TYPE)
|
||||
.icon(new IconicsDrawable(activity)
|
||||
.icon(CommunityMaterial.Icon2.cmd_information)
|
||||
.icon(CommunityMaterial.Icon2.cmd_information_outline)
|
||||
.color(IconicsColor.colorInt(primaryTextOnPrimaryBg))
|
||||
.size(IconicsSize.dp(iconSizeDp)))
|
||||
.build();
|
||||
@ -1133,7 +1134,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
.textColor(primaryTextOnPrimaryBg)
|
||||
.subTextColor(secondaryTextOnPrimaryBg)
|
||||
.icon(new IconicsDrawable(activity)
|
||||
.icon(CommunityMaterial.Icon2.cmd_shield_half_full)
|
||||
.icon(CommunityMaterial.Icon2.cmd_shield_outline)
|
||||
.color(IconicsColor.colorInt(primaryTextOnPrimaryBg))
|
||||
.size(IconicsSize.dp(iconSizeDp)))
|
||||
.setOnClickAction(ConvenienceBuilder.createWebsiteOnClickAction(activity, Uri.parse("https://szkolny.eu/privacy-policy")))
|
||||
@ -1145,7 +1146,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
.subTextColor(secondaryTextOnPrimaryBg)
|
||||
.subText(R.string.settings_about_discord_subtext)
|
||||
.icon(new IconicsDrawable(activity)
|
||||
.icon(CommunityMaterial.Icon.cmd_discord)
|
||||
.icon(SzkolnyFont.Icon.szf_discord_outline)
|
||||
.color(IconicsColor.colorInt(primaryTextOnPrimaryBg))
|
||||
.size(IconicsSize.dp(iconSizeDp)))
|
||||
.setOnClickAction(ConvenienceBuilder.createWebsiteOnClickAction(activity, Uri.parse("https://discord.gg/n9e8pWr")))
|
||||
@ -1270,7 +1271,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
.textColor(primaryTextOnPrimaryBg)
|
||||
.subTextColor(secondaryTextOnPrimaryBg)
|
||||
.icon(new IconicsDrawable(activity)
|
||||
.icon(CommunityMaterial.Icon.cmd_bug)
|
||||
.icon(CommunityMaterial.Icon.cmd_bug_outline)
|
||||
.color(IconicsColor.colorInt(primaryTextOnPrimaryBg))
|
||||
.size(IconicsSize.dp(iconSizeDp)))
|
||||
.setOnClickAction(() -> {
|
||||
|
@ -37,6 +37,7 @@ import androidx.viewpager.widget.ViewPager;
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
|
||||
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
@ -103,7 +104,7 @@ public class TimetableFragment extends Fragment {
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_add_event)
|
||||
.withDescription(R.string.menu_add_event_desc)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_calendar_plus)
|
||||
.withIcon(SzkolnyFont.Icon.szf_calendar_plus_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
new MaterialDialog.Builder(activity)
|
||||
@ -132,7 +133,7 @@ public class TimetableFragment extends Fragment {
|
||||
new BottomSheetSeparatorItem(true),
|
||||
new BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_mark_as_read)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||
.withOnClickListener(v3 -> {
|
||||
activity.getBottomSheet().close();
|
||||
AsyncTask.execute(() -> app.db.metadataDao().setAllSeen(App.profileId, TYPE_LESSON_CHANGE, true));
|
||||
@ -183,7 +184,7 @@ public class TimetableFragment extends Fragment {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
List<LessonFull> lessons = app.db.lessonDao().getAllWeekNow(App.profileId, today.clone().stepForward(0, 0, -today.getWeekDay()), today);
|
||||
List<LessonFull> lessons = app.db.lessonDao().getAllWeekNow(App.profileId, today.getWeekStart(), today);
|
||||
displayingDate = HomeFragment.findDateWithLessons(App.profileId, lessons);
|
||||
pageSelection = app.appConfig.timetableDisplayDaysBackward + Date.diffDays(displayingDate, today); // DEFAULT HERE
|
||||
|
||||
|
@ -4,30 +4,47 @@ import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.AsyncTask
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import com.google.android.material.datepicker.MaterialDatePicker
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
|
||||
import kotlinx.coroutines.*
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_TYPE_LIBRUS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentTimetableV2Binding
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class TimetableFragment : Fragment() {
|
||||
class TimetableFragment : Fragment(), CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "TimetableFragment"
|
||||
const val ACTION_SCROLL_TO_DATE = "pl.szczodrzynski.edziennik.timetable.SCROLL_TO_DATE"
|
||||
const val DEFAULT_START_HOUR = 6
|
||||
const val DEFAULT_END_HOUR = 19
|
||||
var pageSelection: Date? = null
|
||||
}
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var b: FragmentTimetableV2Binding
|
||||
|
||||
private lateinit var job: Job
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
private var fabShown = false
|
||||
private val items = mutableListOf<Date>()
|
||||
|
||||
@ -36,11 +53,13 @@ class TimetableFragment : Fragment() {
|
||||
if (context == null)
|
||||
return null
|
||||
app = activity.application as App
|
||||
job = Job()
|
||||
context!!.theme.applyStyle(Themes.appTheme, true)
|
||||
if (app.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false)
|
||||
// activity, context and profile is valid
|
||||
b = FragmentTimetableV2Binding.inflate(inflater)
|
||||
b.refreshLayout.setParent(activity.swipeRefreshLayout)
|
||||
return b.root
|
||||
}
|
||||
|
||||
@ -62,48 +81,64 @@ class TimetableFragment : Fragment() {
|
||||
activity.unregisterReceiver(broadcastReceiver)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { launch {
|
||||
// TODO check if app, activity, b can be null
|
||||
if (app.profile == null || !isAdded)
|
||||
return
|
||||
return@launch
|
||||
|
||||
if (app.profile.loginStoreType == LOGIN_TYPE_LIBRUS && app.profile.getLoginData("timetableNotPublic", false)) {
|
||||
b.timetableLayout.visibility = View.GONE
|
||||
b.timetableNotPublicLayout.visibility = View.VISIBLE
|
||||
return
|
||||
return@launch
|
||||
}
|
||||
b.timetableLayout.visibility = View.VISIBLE
|
||||
b.timetableNotPublicLayout.visibility = View.GONE
|
||||
|
||||
items.clear()
|
||||
|
||||
val monthDayCount = listOf(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
|
||||
|
||||
val today = Date.getToday().value
|
||||
val yearStart = app.profile.dateSemester1Start?.clone() ?: return
|
||||
val yearEnd = app.profile.dateYearEnd ?: return
|
||||
while (yearStart.value <= yearEnd.value) {
|
||||
items += yearStart.clone()
|
||||
var maxDays = monthDayCount[yearStart.month-1]
|
||||
if (yearStart.month == 2 && yearStart.isLeap)
|
||||
maxDays++
|
||||
yearStart.day++
|
||||
if (yearStart.day > maxDays) {
|
||||
yearStart.day = 1
|
||||
yearStart.month++
|
||||
}
|
||||
if (yearStart.month > 12) {
|
||||
yearStart.month = 1
|
||||
yearStart.year++
|
||||
}
|
||||
}
|
||||
var startHour = DEFAULT_START_HOUR
|
||||
var endHour = DEFAULT_END_HOUR
|
||||
val deferred = async(Dispatchers.Default) {
|
||||
items.clear()
|
||||
|
||||
val pagerAdapter = TimetablePagerAdapter(fragmentManager ?: return, items)
|
||||
val monthDayCount = listOf(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
|
||||
|
||||
val yearStart = app.profile.dateSemester1Start?.clone() ?: return@async
|
||||
val yearEnd = app.profile.dateYearEnd ?: return@async
|
||||
while (yearStart.value <= yearEnd.value) {
|
||||
items += yearStart.clone()
|
||||
var maxDays = monthDayCount[yearStart.month-1]
|
||||
if (yearStart.month == 2 && yearStart.isLeap)
|
||||
maxDays++
|
||||
yearStart.day++
|
||||
if (yearStart.day > maxDays) {
|
||||
yearStart.day = 1
|
||||
yearStart.month++
|
||||
}
|
||||
if (yearStart.month > 12) {
|
||||
yearStart.month = 1
|
||||
yearStart.year++
|
||||
}
|
||||
}
|
||||
|
||||
val lessonRanges = app.db.lessonRangeDao().getAllNow(App.profileId)
|
||||
startHour = lessonRanges.map { it.startTime.hour }.min() ?: DEFAULT_START_HOUR
|
||||
endHour = lessonRanges.map { it.endTime.hour }.max()?.plus(1) ?: DEFAULT_END_HOUR
|
||||
}
|
||||
deferred.await()
|
||||
|
||||
val pagerAdapter = TimetablePagerAdapter(
|
||||
fragmentManager ?: return@launch,
|
||||
items,
|
||||
startHour,
|
||||
endHour
|
||||
)
|
||||
b.viewPager.offscreenPageLimit = 2
|
||||
b.viewPager.adapter = pagerAdapter
|
||||
b.viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {
|
||||
override fun onPageScrollStateChanged(state: Int) {
|
||||
|
||||
if (b.refreshLayout != null) {
|
||||
b.refreshLayout.isEnabled = state == ViewPager.SCROLL_STATE_IDLE
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
|
||||
@ -111,6 +146,7 @@ class TimetableFragment : Fragment() {
|
||||
}
|
||||
|
||||
override fun onPageSelected(position: Int) {
|
||||
pageSelection = items[position]
|
||||
activity.navView.bottomBar.fabEnable = items[position].value != today
|
||||
if (activity.navView.bottomBar.fabEnable && !fabShown) {
|
||||
activity.gainAttentionFAB()
|
||||
@ -122,11 +158,40 @@ class TimetableFragment : Fragment() {
|
||||
b.tabLayout.setUpWithViewPager(b.viewPager)
|
||||
b.tabLayout.setCurrentItem(items.indexOfFirst { it.value == today }, false)
|
||||
|
||||
activity.navView.bottomSheet.prependItems(
|
||||
BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.timetable_select_day)
|
||||
.withIcon(SzkolnyFont.Icon.szf_calendar_today_outline)
|
||||
.withOnClickListener(View.OnClickListener {
|
||||
activity.bottomSheet.close()
|
||||
MaterialDatePicker.Builder
|
||||
.datePicker()
|
||||
.setSelection(Date.getToday().inMillis)
|
||||
.build()
|
||||
.apply {
|
||||
addOnPositiveButtonClickListener { dateInMillis ->
|
||||
val dateSelected = Date.fromMillis(dateInMillis)
|
||||
b.tabLayout.setCurrentItem(items.indexOfFirst { it == dateSelected }, true)
|
||||
}
|
||||
show(this@TimetableFragment.activity.supportFragmentManager, "MaterialDatePicker")
|
||||
}
|
||||
}),
|
||||
BottomSheetSeparatorItem(true),
|
||||
BottomSheetPrimaryItem(true)
|
||||
.withTitle(R.string.menu_mark_as_read)
|
||||
.withIcon(CommunityMaterial.Icon.cmd_eye_check_outline)
|
||||
.withOnClickListener(View.OnClickListener {
|
||||
activity.bottomSheet.close()
|
||||
AsyncTask.execute { app.db.metadataDao().setAllSeen(App.profileId, Metadata.TYPE_LESSON_CHANGE, true) }
|
||||
Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show()
|
||||
})
|
||||
)
|
||||
|
||||
//activity.navView.bottomBar.fabEnable = true
|
||||
activity.navView.bottomBar.fabExtendedText = getString(pl.szczodrzynski.edziennik.R.string.timetable_today)
|
||||
activity.navView.bottomBar.fabIcon = CommunityMaterial.Icon.cmd_calendar_today
|
||||
activity.navView.bottomBar.fabExtendedText = getString(R.string.timetable_today)
|
||||
activity.navView.bottomBar.fabIcon = SzkolnyFont.Icon.szf_calendar_today_outline
|
||||
activity.navView.setFabOnClickListener(View.OnClickListener {
|
||||
b.tabLayout.setCurrentItem(items.indexOfFirst { it.value == today }, true)
|
||||
})
|
||||
}
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
@ -8,19 +8,26 @@ import pl.szczodrzynski.edziennik.ui.modules.timetable.v2.day.TimetableDayFragme
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||
|
||||
class TimetablePagerAdapter(val fragmentManager: FragmentManager, val items: List<Date>) : FragmentStatePagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
|
||||
class TimetablePagerAdapter(
|
||||
fragmentManager: FragmentManager,
|
||||
private val items: List<Date>,
|
||||
private val startHour: Int,
|
||||
private val endHour: Int
|
||||
) : FragmentStatePagerAdapter(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
|
||||
companion object {
|
||||
private const val TAG = "TimetablePagerAdapter"
|
||||
}
|
||||
|
||||
private val today by lazy { Date.getToday() }
|
||||
private val weekStart by lazy { today.clone().stepForward(0, 0, -today.weekDay) }
|
||||
private val weekStart by lazy { today.weekStart }
|
||||
private val weekEnd by lazy { weekStart.clone().stepForward(0, 0, 6) }
|
||||
|
||||
override fun getItem(position: Int): Fragment {
|
||||
return TimetableDayFragment().apply {
|
||||
arguments = Bundle().apply {
|
||||
putInt("date", items[position].value)
|
||||
putInt("startHour", startHour)
|
||||
putInt("endHour", endHour)
|
||||
}
|
||||
}
|
||||
/*return TimetableDayFragment().apply {
|
||||
@ -42,4 +49,4 @@ class TimetablePagerAdapter(val fragmentManager: FragmentManager, val items: Lis
|
||||
}
|
||||
return pageTitle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,42 +7,97 @@ import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.TextView
|
||||
import androidx.asynclayoutinflater.view.AsyncLayoutInflater
|
||||
import androidx.core.view.setPadding
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.Observer
|
||||
import com.linkedin.android.tachyon.DayView
|
||||
import com.linkedin.android.tachyon.DayViewConfig
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_TYPE_LIBRUS
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.task.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.timetable.LessonFull
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentTimetableV2DayBinding
|
||||
import pl.szczodrzynski.edziennik.databinding.TimetableLessonBinding
|
||||
import pl.szczodrzynski.edziennik.databinding.TimetableNoTimetableBinding
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.timetable.LessonDetailsDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.timetable.v2.TimetableFragment.Companion.DEFAULT_END_HOUR
|
||||
import pl.szczodrzynski.edziennik.ui.modules.timetable.v2.TimetableFragment.Companion.DEFAULT_START_HOUR
|
||||
import pl.szczodrzynski.edziennik.utils.ListenerScrollView
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.navlib.getColorFromAttr
|
||||
import java.util.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.math.min
|
||||
|
||||
class TimetableDayFragment() : Fragment() {
|
||||
class TimetableDayFragment : Fragment(), CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "TimetableDayFragment"
|
||||
}
|
||||
|
||||
private lateinit var app: App
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var b: FragmentTimetableV2DayBinding
|
||||
private lateinit var inflater: AsyncLayoutInflater
|
||||
|
||||
private lateinit var job: Job
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
private lateinit var date: Date
|
||||
private var startHour = DEFAULT_START_HOUR
|
||||
private var endHour = DEFAULT_END_HOUR
|
||||
private var firstEventMinute = 24*60
|
||||
|
||||
// find SwipeRefreshLayout in the hierarchy
|
||||
private val refreshLayout by lazy { view?.findParentById(R.id.refreshLayout) }
|
||||
// the day ScrollView
|
||||
private val dayScrollDelegate = lazy {
|
||||
val dayScroll = ListenerScrollView(context!!)
|
||||
dayScroll.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
dayScroll.setOnRefreshLayoutEnabledListener { enabled ->
|
||||
refreshLayout?.isEnabled = enabled
|
||||
}
|
||||
dayScroll
|
||||
}
|
||||
private val dayScroll by dayScrollDelegate
|
||||
// the lesson DayView
|
||||
private val dayView by lazy {
|
||||
val dayView = DayView(context!!, DayViewConfig(
|
||||
startHour = startHour,
|
||||
endHour = endHour,
|
||||
dividerHeight = 1.dp,
|
||||
halfHourHeight = 60.dp,
|
||||
hourDividerColor = R.attr.hourDividerColor.resolveAttr(context),
|
||||
halfHourDividerColor = R.attr.halfHourDividerColor.resolveAttr(context),
|
||||
hourLabelWidth = 40.dp,
|
||||
hourLabelMarginEnd = 10.dp,
|
||||
eventMargin = 2.dp
|
||||
), true)
|
||||
dayView.setPadding(10.dp)
|
||||
dayScroll.layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
dayScroll.addView(dayView)
|
||||
dayView
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
activity = (getActivity() as MainActivity?) ?: return null
|
||||
if (context == null)
|
||||
return null
|
||||
app = activity.application as App
|
||||
b = FragmentTimetableV2DayBinding.inflate(inflater)
|
||||
job = Job()
|
||||
this.inflater = AsyncLayoutInflater(context!!)
|
||||
date = arguments?.getInt("date")?.let { Date.fromValue(it) } ?: Date.getToday()
|
||||
return b.root
|
||||
startHour = arguments?.getInt("startHour") ?: DEFAULT_START_HOUR
|
||||
endHour = arguments?.getInt("endHour") ?: DEFAULT_END_HOUR
|
||||
return FrameLayout(activity).apply {
|
||||
layoutParams = FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
@ -52,45 +107,42 @@ class TimetableDayFragment() : Fragment() {
|
||||
|
||||
Log.d(TAG, "onViewCreated, date=$date")
|
||||
|
||||
// Inflate a label view for each hour the day view will display
|
||||
val hourLabelViews = ArrayList<View>()
|
||||
for (i in b.day.startHour..b.day.endHour) {
|
||||
val hourLabelView = layoutInflater.inflate(R.layout.timetable_hour_label, b.day, false) as TextView
|
||||
hourLabelView.text = "$i:00"
|
||||
hourLabelViews.add(hourLabelView)
|
||||
}
|
||||
b.day.setHourLabelViews(hourLabelViews)
|
||||
|
||||
// observe lesson database
|
||||
app.db.timetableDao().getForDate(App.profileId, date).observe(this, Observer<List<LessonFull>> { lessons ->
|
||||
buildLessonViews(lessons)
|
||||
processLessonList(lessons)
|
||||
})
|
||||
}
|
||||
|
||||
private fun buildLessonViews(lessons: List<LessonFull>) {
|
||||
private fun processLessonList(lessons: List<LessonFull>) {
|
||||
// no lessons - timetable not downloaded yet
|
||||
if (lessons.isEmpty()) {
|
||||
b.dayScroll.visibility = View.GONE
|
||||
b.noTimetableLayout.visibility = View.VISIBLE
|
||||
b.noLessonsLayout.visibility = View.GONE
|
||||
val weekStart = date.clone().stepForward(0, 0, -date.weekDay).stringY_m_d
|
||||
b.noTimetableSync.onClick {
|
||||
it.isEnabled = false
|
||||
EdziennikTask.syncProfile(
|
||||
profileId = App.profileId,
|
||||
viewIds = listOf(
|
||||
DRAWER_ITEM_TIMETABLE to 0
|
||||
),
|
||||
arguments = JsonObject(
|
||||
"weekStart" to weekStart
|
||||
)
|
||||
).enqueue(activity)
|
||||
inflater.inflate(R.layout.timetable_no_timetable, view as FrameLayout) { view, _, parent ->
|
||||
parent?.removeAllViews()
|
||||
parent?.addView(view)
|
||||
val b = TimetableNoTimetableBinding.bind(view)
|
||||
val weekStart = date.weekStart.stringY_m_d
|
||||
b.noTimetableSync.onClick {
|
||||
it.isEnabled = false
|
||||
EdziennikTask.syncProfile(
|
||||
profileId = App.profileId,
|
||||
viewIds = listOf(
|
||||
DRAWER_ITEM_TIMETABLE to 0
|
||||
),
|
||||
arguments = JsonObject(
|
||||
"weekStart" to weekStart
|
||||
)
|
||||
).enqueue(activity)
|
||||
}
|
||||
b.noTimetableWeek.setText(R.string.timetable_no_timetable_week, weekStart)
|
||||
}
|
||||
b.noTimetableWeek.setText(R.string.timetable_no_timetable_week, weekStart)
|
||||
return
|
||||
}
|
||||
// one lesson indicating a day without lessons
|
||||
if (lessons.size == 1 && lessons[0].type == Lesson.TYPE_NO_LESSONS) {
|
||||
b.dayScroll.visibility = View.GONE
|
||||
b.noTimetableLayout.visibility = View.GONE
|
||||
b.noLessonsLayout.visibility = View.VISIBLE
|
||||
inflater.inflate(R.layout.timetable_no_lessons, view as FrameLayout) { view, _, parent ->
|
||||
parent?.removeAllViews()
|
||||
parent?.addView(view)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@ -101,23 +153,37 @@ class TimetableDayFragment() : Fragment() {
|
||||
return
|
||||
}
|
||||
|
||||
b.dayScroll.visibility = View.VISIBLE
|
||||
b.noTimetableLayout.visibility = View.GONE
|
||||
b.noLessonsLayout.visibility = View.GONE
|
||||
// clear the root view and add the ScrollView
|
||||
(view as FrameLayout).removeAllViews()
|
||||
(view as FrameLayout).addView(dayScroll)
|
||||
|
||||
var firstEventMinute = 24*60
|
||||
// Inflate a label view for each hour the day view will display
|
||||
val hourLabelViews = ArrayList<View>()
|
||||
for (i in dayView.startHour..dayView.endHour) {
|
||||
val hourLabelView = layoutInflater.inflate(R.layout.timetable_hour_label, dayView, false) as TextView
|
||||
hourLabelView.text = "$i:00"
|
||||
hourLabelViews.add(hourLabelView)
|
||||
}
|
||||
dayView.setHourLabelViews(hourLabelViews)
|
||||
|
||||
buildLessonViews(lessons)
|
||||
}
|
||||
|
||||
private fun buildLessonViews(lessons: List<LessonFull>) {
|
||||
if (!isAdded)
|
||||
return
|
||||
|
||||
val eventViews = mutableListOf<View>()
|
||||
val eventTimeRanges = mutableListOf<DayView.EventTimeRange>()
|
||||
|
||||
// Reclaim all of the existing event views so we can reuse them if needed, this process
|
||||
// can be useful if your day view is hosted in a recycler view for example
|
||||
val recycled = b.day.removeEventViews()
|
||||
val recycled = dayView.removeEventViews()
|
||||
var remaining = recycled?.size ?: 0
|
||||
|
||||
val arrowRight = " → "
|
||||
val bullet = " • "
|
||||
val colorSecondary = getColorFromAttr(activity, android.R.attr.textColorSecondary)
|
||||
val colorSecondary = android.R.attr.textColorSecondary.resolveAttr(activity)
|
||||
|
||||
for (lesson in lessons) {
|
||||
val startTime = lesson.displayStartTime ?: continue
|
||||
@ -127,7 +193,7 @@ class TimetableDayFragment() : Fragment() {
|
||||
|
||||
// Try to recycle an existing event view if there are enough left, otherwise inflate
|
||||
// a new one
|
||||
val eventView = (if (remaining > 0) recycled?.get(--remaining) else layoutInflater.inflate(R.layout.timetable_lesson, b.day, false))
|
||||
val eventView = (if (remaining > 0) recycled?.get(--remaining) else layoutInflater.inflate(R.layout.timetable_lesson, dayView, false))
|
||||
?: continue
|
||||
val lb = TimetableLessonBinding.bind(eventView)
|
||||
eventViews += eventView
|
||||
@ -181,6 +247,8 @@ class TimetableDayFragment() : Fragment() {
|
||||
lb.detailsFirst.text = listOfNotEmpty(timeRange, classroomInfo).concat(bullet)
|
||||
lb.detailsSecond.text = listOfNotEmpty(teacherInfo, teamInfo).concat(bullet)
|
||||
|
||||
lb.unread = lesson.type != Lesson.TYPE_NORMAL && !lesson.seen
|
||||
|
||||
//lb.subjectName.typeface = Typeface.create("sans-serif-light", Typeface.BOLD)
|
||||
when (lesson.type) {
|
||||
Lesson.TYPE_NORMAL -> {
|
||||
@ -274,9 +342,16 @@ class TimetableDayFragment() : Fragment() {
|
||||
eventTimeRanges.add(DayView.EventTimeRange(startMinute, endMinute))
|
||||
}
|
||||
|
||||
val minuteHeight = (b.day.getHourTop(1) - b.day.getHourTop(0)).toFloat() / 60f
|
||||
val firstEventTop = (firstEventMinute - b.day.startHour * 60) * minuteHeight
|
||||
b.day.setEventViews(eventViews, eventTimeRanges)
|
||||
b.dayScroll.scrollTo(0, firstEventTop.toInt())
|
||||
dayView.setEventViews(eventViews, eventTimeRanges)
|
||||
val firstEventTop = (firstEventMinute - dayView.startHour * 60) * dayView.minuteHeight
|
||||
dayScroll.scrollTo(0, firstEventTop.toInt())
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (dayScrollDelegate.isInitialized()) {
|
||||
val firstEventTop = (firstEventMinute - dayView.startHour * 60) * dayView.minuteHeight
|
||||
dayScroll.scrollTo(0, firstEventTop.toInt())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-16.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.widget.ScrollView
|
||||
|
||||
class ListenerScrollView(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null
|
||||
) : ScrollView(context, attrs) {
|
||||
|
||||
private var onScrollChangedListener: ((v: ListenerScrollView, scrollX: Int, scrollY: Int, oldScrollX: Int, oldScrollY: Int) -> Unit)? = null
|
||||
private var onRefreshLayoutEnabledListener: ((enabled: Boolean) -> Unit)? = null
|
||||
private var refreshLayoutEnabled = true
|
||||
|
||||
init {
|
||||
setOnTouchListener { _, event ->
|
||||
if (event.action == MotionEvent.ACTION_UP) {
|
||||
refreshLayoutEnabled = scrollY < 10
|
||||
onRefreshLayoutEnabledListener?.invoke(refreshLayoutEnabled)
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun onScrollChanged(l: Int, t: Int, oldl: Int, oldt: Int) {
|
||||
onScrollChangedListener?.invoke(this, l, t, oldl, oldt)
|
||||
if (t > 10 && refreshLayoutEnabled) {
|
||||
refreshLayoutEnabled = false
|
||||
onRefreshLayoutEnabledListener?.invoke(refreshLayoutEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
fun setOnScrollChangedListener(l: ((v: ListenerScrollView, scrollX: Int, scrollY: Int, oldScrollX: Int, oldScrollY: Int) -> Unit)?) {
|
||||
onScrollChangedListener = l
|
||||
}
|
||||
|
||||
fun setOnRefreshLayoutEnabledListener(l: ((enabled: Boolean) -> Unit)?) {
|
||||
onRefreshLayoutEnabledListener = l
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-22.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
|
||||
public class SimpleDividerItemDecoration extends RecyclerView.ItemDecoration {
|
||||
private Drawable mDivider;
|
||||
|
||||
public SimpleDividerItemDecoration(Context context) {
|
||||
mDivider = context.getResources().getDrawable(R.drawable.divider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
|
||||
int left = parent.getPaddingLeft();
|
||||
int right = parent.getWidth() - parent.getPaddingRight();
|
||||
|
||||
int childCount = parent.getChildCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
View child = parent.getChildAt(i);
|
||||
|
||||
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
|
||||
|
||||
int top = child.getBottom() + params.bottomMargin;
|
||||
int bottom = top + mDivider.getIntrinsicHeight();
|
||||
|
||||
mDivider.setBounds(left, top, right, bottom);
|
||||
mDivider.draw(c);
|
||||
}
|
||||
}
|
||||
}
|
@ -75,21 +75,22 @@ class TextInputDropDown : TextInputEditText {
|
||||
}
|
||||
}
|
||||
|
||||
fun select(item: Item) {
|
||||
fun select(item: Item): Item? {
|
||||
selected = item
|
||||
updateText()
|
||||
return item
|
||||
}
|
||||
|
||||
fun select(id: Long?) {
|
||||
items.singleOrNull { it.id == id }?.let { select(it) }
|
||||
fun select(id: Long?): Item? {
|
||||
return items.singleOrNull { it.id == id }?.let { select(it) }
|
||||
}
|
||||
|
||||
fun select(tag: Any?) {
|
||||
items.singleOrNull { it.tag == tag }?.let { select(it) }
|
||||
fun select(tag: Any?): Item? {
|
||||
return items.singleOrNull { it.tag == tag }?.let { select(it) }
|
||||
}
|
||||
|
||||
fun select(index: Int) {
|
||||
items.getOrNull(index)?.let { select(it) }
|
||||
fun select(index: Int): Item? {
|
||||
return items.getOrNull(index)?.let { select(it) }
|
||||
}
|
||||
|
||||
fun deselect(): TextInputDropDown {
|
||||
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-22.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Rect
|
||||
import android.util.AttributeSet
|
||||
import android.view.KeyEvent
|
||||
import android.view.KeyEvent.KEYCODE_BACK
|
||||
import androidx.annotation.NonNull
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
|
||||
class TextInputKeyboardEdit : TextInputEditText {
|
||||
|
||||
/**
|
||||
* Keyboard Listener
|
||||
*/
|
||||
internal var listener: KeyboardListener? = null
|
||||
|
||||
constructor(context: Context) : super(context)
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
|
||||
|
||||
override fun onFocusChanged(focused: Boolean, direction: Int, previouslyFocusedRect: Rect?) {
|
||||
super.onFocusChanged(focused, direction, previouslyFocusedRect)
|
||||
if (listener != null)
|
||||
listener!!.onStateChanged(this, true)
|
||||
}
|
||||
|
||||
override fun onKeyPreIme(keyCode: Int, @NonNull event: KeyEvent): Boolean {
|
||||
if (event.keyCode == KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) {
|
||||
if (listener != null)
|
||||
listener!!.onStateChanged(this, false)
|
||||
|
||||
// Hide cursor
|
||||
isFocusable = false
|
||||
|
||||
// Set EditText to be focusable again
|
||||
isFocusable = true
|
||||
isFocusableInTouchMode = true
|
||||
}
|
||||
return super.onKeyPreIme(keyCode, event)
|
||||
}
|
||||
|
||||
fun setOnKeyboardListener(listener: KeyboardListener) {
|
||||
this.listener = listener
|
||||
}
|
||||
|
||||
interface KeyboardListener {
|
||||
fun onStateChanged(keyboardEditText: TextInputKeyboardEdit, showing: Boolean)
|
||||
}
|
||||
}
|
@ -95,6 +95,7 @@ public class AppConfig {
|
||||
public String updateUrl = "";
|
||||
public String updateFilename = "";
|
||||
public boolean updateMandatory = false;
|
||||
public boolean updateDirect = false;
|
||||
|
||||
public boolean webPushEnabled = false;
|
||||
|
||||
|
@ -41,6 +41,10 @@ public class Date implements Comparable<Date> {
|
||||
return new Date(this.year, this.month, this.day);
|
||||
}
|
||||
|
||||
public Date getWeekStart() {
|
||||
return clone().stepForward(0, 0, -getWeekDay());
|
||||
}
|
||||
|
||||
public static Date fromYmd(String dateTime) {
|
||||
return new Date(Integer.parseInt(dateTime.substring(0, 4)), Integer.parseInt(dateTime.substring(4, 6)), Integer.parseInt(dateTime.substring(6, 8)));
|
||||
}
|
||||
@ -134,11 +138,23 @@ public class Date implements Comparable<Date> {
|
||||
|
||||
public Date stepForward(int years, int months, int days) {
|
||||
this.day += days;
|
||||
if (day <= 0) {
|
||||
month--;
|
||||
if(month <= 0) {
|
||||
month += 12;
|
||||
year--;
|
||||
}
|
||||
day += daysInMonth();
|
||||
}
|
||||
if (day > daysInMonth()) {
|
||||
day -= daysInMonth();
|
||||
month++;
|
||||
}
|
||||
this.month += months;
|
||||
if(month <= 0) {
|
||||
month += 12;
|
||||
year--;
|
||||
}
|
||||
if (month > 12) {
|
||||
month -= 12;
|
||||
year++;
|
||||
@ -176,6 +192,7 @@ public class Date implements Comparable<Date> {
|
||||
public boolean isLeap() {
|
||||
return ((year & 3) == 0) && ((year % 100) != 0 || (year % 400) == 0);
|
||||
}
|
||||
|
||||
public int daysInMonth() {
|
||||
switch (month) {
|
||||
case 1:
|
||||
|
@ -117,7 +117,7 @@ public class WidgetNotifications extends AppWidgetProvider {
|
||||
.color(IconicsColor.colorInt(Color.WHITE))
|
||||
.size(IconicsSize.dp(widgetConfig.bigStyle ? 24 : 16)).toBitmap());
|
||||
|
||||
views.setImageViewBitmap(R.id.widgetNotificationsSync, new IconicsDrawable(context, CommunityMaterial.Icon2.cmd_sync)
|
||||
views.setImageViewBitmap(R.id.widgetNotificationsSync, new IconicsDrawable(context, CommunityMaterial.Icon.cmd_download_outline)
|
||||
.color(IconicsColor.colorInt(Color.WHITE))
|
||||
.size(IconicsSize.dp(widgetConfig.bigStyle ? 24 : 16)).toBitmap());
|
||||
|
||||
|
@ -173,7 +173,8 @@ public class WidgetTimetableListProvider implements RemoteViewsService.RemoteVie
|
||||
intent.putExtra("endTime", lesson.endTime.getStringValue());
|
||||
views.setOnClickFillInIntent(R.id.widgetTimetableRoot, intent);
|
||||
|
||||
views.setTextViewText(R.id.widgetTimetableTime, lesson.startTime.getStringHM() + " - " + lesson.endTime.getStringHM());
|
||||
if (lesson.startTime != null && lesson.endTime != null)
|
||||
views.setTextViewText(R.id.widgetTimetableTime, lesson.startTime.getStringHM() + " - " + lesson.endTime.getStringHM());
|
||||
|
||||
views.setViewVisibility(R.id.widgetTimetableEvent1, View.GONE);
|
||||
views.setViewVisibility(R.id.widgetTimetableEvent2, View.GONE);
|
||||
|
15
app/src/main/res/drawable/divider.xml
Normal file
15
app/src/main/res/drawable/divider.xml
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) Kuba Szczodrzyński 2019-11-22.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<size
|
||||
android:width="1dp"
|
||||
android:height="1dp" />
|
||||
|
||||
<solid android:color="@color/dividerColor" />
|
||||
|
||||
</shape>
|
BIN
app/src/main/res/drawable/header.png
Normal file
BIN
app/src/main/res/drawable/header.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 62 KiB |
37
app/src/main/res/drawable/ic_no_notifications.xml
Normal file
37
app/src/main/res/drawable/ic_no_notifications.xml
Normal file
@ -0,0 +1,37 @@
|
||||
<!--
|
||||
~ Copyright (c) Kuba Szczodrzyński 2019-11-22.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="128dp"
|
||||
android:height="128dp"
|
||||
android:viewportWidth="128"
|
||||
android:viewportHeight="128">
|
||||
<path
|
||||
android:pathData="m104,18h-80c-5.523,0 -10,4.477 -10,10v84.699c0,2.93 2.371,5.301 5.301,5.301h0.012c1.691,0 3.277,-0.805 4.277,-2.164l10.082,-13.75c1.883,-2.566 4.875,-4.086 8.063,-4.086h62.266c5.523,0 10,-4.477 10,-10v-60c0,-5.523 -4.477,-10 -10,-10z"
|
||||
android:fillColor="#2babee"/>
|
||||
<path
|
||||
android:pathData="m128,104c0,13.254 -10.746,24 -24,24 -13.254,0 -24,-10.746 -24,-24s10.746,-24 24,-24c13.254,0 24,10.746 24,24z"
|
||||
android:fillColor="#fc556c"/>
|
||||
<path
|
||||
android:pathData="m114.84,98.824 l-16.012,16.012c-1.555,1.555 -4.102,1.555 -5.656,0 -1.555,-1.559 -1.555,-4.106 0,-5.656l16.012,-16.012c1.555,-1.555 4.102,-1.555 5.656,0 1.551,1.555 1.551,4.102 0,5.656z"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="m93.164,98.824 l16.012,16.012c1.555,1.555 4.102,1.555 5.656,0 1.555,-1.559 1.555,-4.106 0,-5.656l-16.012,-16.012c-1.555,-1.555 -4.102,-1.555 -5.656,0 -1.551,1.555 -1.551,4.102 0,5.656z"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="m74,78h-36c-2.211,0 -4,-1.789 -4,-4 0,-2.211 1.789,-4 4,-4h36c2.211,0 4,1.789 4,4 0,2.211 -1.789,4 -4,4z"
|
||||
android:fillColor="#f1fcff"/>
|
||||
<path
|
||||
android:pathData="m72,54h18c2.211,0 4,1.789 4,4 0,2.211 -1.789,4 -4,4h-18c-2.211,0 -4,-1.789 -4,-4 0,-2.211 1.789,-4 4,-4z"
|
||||
android:fillColor="#f1fcff"/>
|
||||
<path
|
||||
android:pathData="m38,54h20c2.211,0 4,1.789 4,4 0,2.211 -1.789,4 -4,4h-20c-2.211,0 -4,-1.789 -4,-4 0,-2.211 1.789,-4 4,-4z"
|
||||
android:fillColor="#f1fcff"/>
|
||||
<path
|
||||
android:pathData="m38,38h34c2.211,0 4,1.789 4,4 0,2.211 -1.789,4 -4,4h-34c-2.211,0 -4,-1.789 -4,-4 0,-2.211 1.789,-4 4,-4z"
|
||||
android:fillColor="#f1fcff"/>
|
||||
<path
|
||||
android:pathData="m86,38h4c2.211,0 4,1.789 4,4 0,2.211 -1.789,4 -4,4h-4c-2.211,0 -4,-1.789 -4,-4 0,-2.211 1.789,-4 4,-4z"
|
||||
android:fillColor="#f1fcff"/>
|
||||
</vector>
|
@ -1,61 +1,12 @@
|
||||
<!--
|
||||
~ Copyright (c) Kuba Szczodrzyński 2019-11-11.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="128dp"
|
||||
android:height="128dp"
|
||||
android:viewportWidth="128"
|
||||
android:viewportHeight="128">
|
||||
<path
|
||||
android:pathData="m117,76h4c3.852,0 7,-3.148 7,-7 0,-3.852 -3.148,-7 -7,-7h-13c-2.199,0 -4,-1.801 -4,-4s1.801,-4 4,-4h11c3.852,0 7,-3.148 7,-7 0,-3.852 -3.148,-7 -7,-7h-1c-2.211,0 -4,-1.789 -4,-4 0,-2.211 1.789,-4 4,-4h4c3.695,0 6.637,-3.387 5.879,-7.211 -0.566,-2.844 -3.238,-4.789 -6.141,-4.789h-15.738c-1.656,0 -3,-1.344 -3,-3s1.344,-3 3,-3h6.824c2.277,0 4.402,-1.441 4.992,-3.641 0.895,-3.328 -1.625,-6.359 -4.816,-6.359h-96c-3.852,0 -7,3.148 -7,7 0,3.852 3.148,7 7,7h3c2.211,0 4,1.789 4,4 0,2.211 -1.789,4 -4,4h-10.77c-3.34,0 -6.391,2.242 -7.074,5.516 -0.941,4.488 2.508,8.484 6.844,8.484h15l-6,24h-10.77c-3.34,0 -6.391,2.242 -7.074,5.516 -0.941,4.488 2.508,8.484 6.844,8.484h1c2.211,0 4,1.789 4,4 0,2.211 -1.789,4 -4,4h-1c-4.336,0 -7.785,3.996 -6.844,8.484 0.684,3.273 3.734,5.516 7.074,5.516h10.77c2.211,0 4,1.789 4,4s-1.789,4 -4,4h-2.77c-3.34,0 -6.391,2.242 -7.074,5.516 -0.941,4.488 2.508,8.484 6.844,8.484h97c3.313,0 6,-2.688 6,-6s-2.688,-6 -6,-6h-1c-2.762,0 -5,-2.238 -5,-5s2.238,-5 5,-5h6c3.852,0 7,-3.148 7,-7 0,-3.852 -3.148,-7 -7,-7 -2.75,0 -5,-2.25 -5,-5s2.25,-5 5,-5z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:gradientRadius="100.522"
|
||||
android:centerX="63.746"
|
||||
android:centerY="71.138"
|
||||
android:type="radial"
|
||||
android:tileMode="mirror">
|
||||
<item android:offset="0" android:color="#1F0FCCFF"/>
|
||||
<item android:offset="0.1927" android:color="#1F0FCEFF"/>
|
||||
<item android:offset="0.7025" android:color="#1F0FD5FF"/>
|
||||
<item android:offset="1" android:color="#1F0FD7FF"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
android:pathData="m103.24,15.168 l-7.883,7.871c-8.746,-7.063 -19.719,-11.039 -31.355,-11.039 -27.57,0 -50,22.43 -50,50s22.43,50 50,50c17.758,0 34.348,-9.367 43.301,-24.449 1.41,-2.375 0.625,-5.441 -1.75,-6.852 -2.367,-1.41 -5.438,-0.629 -6.852,1.746 -7.156,12.062 -20.453,19.555 -34.699,19.555 -22.055,0 -40,-17.945 -40,-40s17.945,-40 40,-40c8.934,0 17.371,2.938 24.223,8.16l-9.063,9.047c-2.48,2.5 -0.719,6.762 2.801,6.762h24.039c2.199,0 4,-1.801 4,-4v-24c0,-3.52 -4.262,-5.301 -6.762,-2.801z"
|
||||
android:fillColor="#ffcf48"/>
|
||||
<path
|
||||
android:pathData="m103.24,15.168 l-7.883,7.871c-8.746,-7.063 -19.719,-11.039 -31.355,-11.039 -27.57,0 -50,22.43 -50,50 0,27.57 22.43,50 50,50 17.758,0 34.348,-9.367 43.301,-24.449 1.41,-2.375 0.625,-5.441 -1.75,-6.852 -2.367,-1.41 -5.438,-0.629 -6.852,1.746 -7.156,12.062 -20.453,19.555 -34.699,19.555 -22.055,0 -40,-17.945 -40,-40 0,-22.055 17.945,-40 40,-40 8.934,0 17.371,2.938 24.223,8.16l-9.063,9.047c-2.48,2.5 -0.719,6.762 2.801,6.762h24.039c2.199,0 4,-1.801 4,-4v-24c0,-3.52 -4.262,-5.301 -6.762,-2.801z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startY="125.452"
|
||||
android:startX="62"
|
||||
android:endY="6.4762"
|
||||
android:endX="62"
|
||||
android:type="linear"
|
||||
android:tileMode="mirror">
|
||||
<item android:offset="0" android:color="#FFFEAA53"/>
|
||||
<item android:offset="0.6124" android:color="#FFFFCD49"/>
|
||||
<item android:offset="1" android:color="#FFFFDE44"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:pathData="m68,85c0,2.762 -2.238,5 -5,5s-5,-2.238 -5,-5 2.238,-5 5,-5 5,2.238 5,5zM70,41c0,-3.867 -3.133,-7 -7,-7 -3.867,0 -7,3.133 -7,7 0,0.047 0.016,0.094 0.016,0.141h-0.016l2.438,28.59c0.203,2.414 2.188,4.269 4.563,4.269s4.359,-1.855 4.563,-4.269l2.438,-28.59h-0.016c0,-0.047 0.016,-0.094 0.016,-0.141z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startY="90"
|
||||
android:startX="63"
|
||||
android:endY="11.7176"
|
||||
android:endX="63"
|
||||
android:type="linear"
|
||||
android:tileMode="mirror">
|
||||
<item android:offset="0" android:color="#FFFF634D"/>
|
||||
<item android:offset="0.2043" android:color="#FFFE6464"/>
|
||||
<item android:offset="0.5209" android:color="#FFFC6581"/>
|
||||
<item android:offset="0.7936" android:color="#FFFA6694"/>
|
||||
<item android:offset="0.9892" android:color="#FFFA669A"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
android:pathData="m68,85c0,2.762 -2.238,5 -5,5s-5,-2.238 -5,-5 2.238,-5 5,-5 5,2.238 5,5zM70,41c0,-3.867 -3.133,-7 -7,-7s-7,3.133 -7,7c0,0.047 0.016,0.094 0.016,0.141h-0.016l2.438,28.59c0.203,2.414 2.188,4.269 4.563,4.269s4.359,-1.855 4.563,-4.269l2.438,-28.59h-0.016c0,-0.047 0.016,-0.094 0.016,-0.141z"
|
||||
android:fillColor="#fd657a"/>
|
||||
</vector>
|
||||
|
@ -1,45 +1,5 @@
|
||||
<!--
|
||||
~ Copyright (c) Kuba Szczodrzyński 2019-11-11.
|
||||
-->
|
||||
|
||||
<vector android:height="128dp" android:viewportHeight="64"
|
||||
android:viewportWidth="64" android:width="128dp"
|
||||
xmlns:aapt="http://schemas.android.com/aapt" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:pathData="m59,16h2c1.848,0 3.319,-1.693 2.94,-3.605 -0.283,-1.423 -1.62,-2.395 -3.071,-2.395h-10.369c-0.828,0 -1.5,-0.672 -1.5,-1.5s0.672,-1.5 1.5,-1.5h5.912c1.139,0 2.202,-0.721 2.497,-1.821 0.446,-1.663 -0.813,-3.179 -2.409,-3.179h-48c-1.925,0 -3.5,1.575 -3.5,3.5s1.575,3.5 3.5,3.5h1.5c1.105,0 2,0.895 2,2s-0.895,2 -2,2h-5.385c-1.67,0 -3.195,1.122 -3.537,2.757 -0.47,2.245 1.254,4.243 3.422,4.243h7.5l-3,12h-5.385c-1.67,0 -3.195,1.122 -3.537,2.757 -0.47,2.245 1.254,4.243 3.422,4.243h0.5c1.105,0 2,0.895 2,2s-0.895,2 -2,2h-0.5c-2.168,0 -3.892,1.998 -3.422,4.243 0.342,1.635 1.867,2.757 3.537,2.757h5.385c1.105,0 2,0.895 2,2s-0.895,2 -2,2h-1.385c-1.67,0 -3.195,1.122 -3.537,2.757 -0.47,2.245 1.254,4.243 3.422,4.243h48.5c1.657,0 3,-1.343 3,-3s-1.343,-3 -3,-3h-0.5c-1.381,0 -2.5,-1.119 -2.5,-2.5s1.119,-2.5 2.5,-2.5h4.5c1.657,0 3,-1.343 3,-3s-1.343,-3 -3,-3h-8.377c2.141,-3.494 3.377,-7.602 3.377,-12 0,-2.441 -0.384,-4.792 -1.088,-7h6.501c1.139,0 2.202,-0.721 2.497,-1.821 0.445,-1.663 -0.814,-3.179 -2.41,-3.179h-1.5c-1.105,0 -2,-0.895 -2,-2s0.895,-2 2,-2z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient android:centerX="32" android:centerY="31.500021"
|
||||
android:gradientRadius="32" android:tileMode="mirror" android:type="radial">
|
||||
<item android:color="#1F0FCCFF" android:offset="0"/>
|
||||
<item android:color="#1F0FCEFF" android:offset="0.193"/>
|
||||
<item android:color="#1F0FD5FF" android:offset="0.703"/>
|
||||
<item android:color="#1F0ECEFF" android:offset="1"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path android:pathData="M51.483,15.326l3.937,-3.93c1.24,-1.25 0.36,-3.38 -1.4,-3.38H42c-1.1,0 -2,0.9 -2,2v12c0,1.76 2.13,2.65 3.38,1.4l4.537,-4.529C50.532,22.313 52,26.533 52,31c0,11.215 -8.565,20 -19.5,20c-1.381,0 -2.5,1.119 -2.5,2.5s1.119,2.5 2.5,2.5C46.238,56 57,45.019 57,31C57,25.183 55.012,19.699 51.483,15.326z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient android:endX="43.5" android:endY="-21.15"
|
||||
android:startX="43.5" android:startY="59.034"
|
||||
android:tileMode="mirror" android:type="linear">
|
||||
<item android:color="#FFFF634D" android:offset="0"/>
|
||||
<item android:color="#FFFE6464" android:offset="0.204"/>
|
||||
<item android:color="#FFFC6581" android:offset="0.521"/>
|
||||
<item android:color="#FFFA6694" android:offset="0.794"/>
|
||||
<item android:color="#FFFA669A" android:offset="0.989"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path android:pathData="M20.604,38.58l-4.523,4.53C13.468,39.683 12,35.463 12,31c0,-11.215 8.565,-20 19.5,-20c1.381,0 2.5,-1.119 2.5,-2.5S32.881,6 31.5,6C17.762,6 7,16.981 7,31c0,5.815 1.989,11.303 5.52,15.677L8.584,50.62c-1.25,1.25 -0.36,3.38 1.4,3.38h12c1.1,0 2,-0.9 2,-2V39.98C23.984,38.22 21.854,37.34 20.604,38.58z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient android:endX="20.5" android:endY="-24.844"
|
||||
android:startX="20.5" android:startY="55.227"
|
||||
android:tileMode="mirror" android:type="linear">
|
||||
<item android:color="#FFFF634D" android:offset="0"/>
|
||||
<item android:color="#FFFE6464" android:offset="0.204"/>
|
||||
<item android:color="#FFFC6581" android:offset="0.521"/>
|
||||
<item android:color="#FFFA6694" android:offset="0.794"/>
|
||||
<item android:color="#FFFA669A" android:offset="0.989"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
android:viewportWidth="64" android:width="128dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#fd646f" android:pathData="m51.483,15.326 l3.937,-3.93c1.24,-1.25 0.36,-3.38 -1.4,-3.38h-12.02c-1.1,0 -2,0.9 -2,2v12c0,1.76 2.13,2.65 3.38,1.4l4.537,-4.529c2.615,3.426 4.083,7.646 4.083,12.113 0,11.215 -8.565,20 -19.5,20 -1.381,0 -2.5,1.119 -2.5,2.5s1.119,2.5 2.5,2.5c13.738,0 24.5,-10.981 24.5,-25 0,-5.817 -1.988,-11.301 -5.517,-15.674z"/>
|
||||
<path android:fillColor="#fd646f" android:pathData="m20.604,38.58 l-4.523,4.53c-2.613,-3.427 -4.081,-7.647 -4.081,-12.11 0,-11.215 8.565,-20 19.5,-20 1.381,0 2.5,-1.119 2.5,-2.5s-1.119,-2.5 -2.5,-2.5c-13.738,0 -24.5,10.981 -24.5,25 0,5.815 1.989,11.303 5.52,15.677l-3.936,3.943c-1.25,1.25 -0.36,3.38 1.4,3.38h12c1.1,0 2,-0.9 2,-2v-12.02c0,-1.76 -2.13,-2.64 -3.38,-1.4z"/>
|
||||
</vector>
|
||||
|
@ -1,202 +1,30 @@
|
||||
<!--
|
||||
~ Copyright (c) Kuba Szczodrzyński 2019-11-11.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="128dp"
|
||||
android:height="128dp"
|
||||
android:viewportWidth="128"
|
||||
android:viewportHeight="128">
|
||||
<path
|
||||
android:pathData="m118,62.129h2.605c3.789,0 7.188,-2.84 7.383,-6.625 0.211,-4.035 -3,-7.375 -6.988,-7.375h-4.805c-1.965,0 -3.785,-1.328 -4.129,-3.262 -0.043,-0.25 -0.066,-0.5 -0.066,-0.746 0.004,-2.168 1.734,-3.93 3.887,-3.988 3.023,-0.082 5.731,-2.293 6.07,-5.297 0.027,-0.242 0.039,-0.477 0.039,-0.711 0,-3.313 -2.688,-5.996 -6,-5.996h-4.602c-0.434,0 -4.863,-0.035 -5.281,-0.105 -0.035,-0.008 -0.074,-0.016 -0.113,-0.023v18h-42v-18h25.715c0.438,-1.688 0.539,-3.512 -0.945,-5.719 -1.836,-2.742 -5.023,-4.281 -8.324,-4.281h-9.445c-1.656,0 -3,-1.344 -3,-3s1.344,-3 3,-3h0.66c3.25,0 6.16,-2.434 6.332,-5.68 0.18,-3.461 -2.57,-6.32 -5.992,-6.32h-57.66c-3.25,0 -6.16,2.434 -6.332,5.68 -0.18,3.457 2.57,6.32 5.992,6.32h15c1.656,0 3,1.344 3,3s-1.344,3 -3,3h-17c-4.418,0 -8,3.582 -8,8s3.582,8 8,8h26v12h-14l2,21.109c-1.07,0.801 -1.836,1.98 -1.973,3.375 -0.184,1.84 0.633,3.5 1.973,4.504v5.047c-0.027,0.148 -0.043,0.297 -0.027,0.449 0.301,2.992 -2.039,5.516 -4.973,5.516h-14.66c-2.984,0 -5.762,2.023 -6.25,4.965 -0.246,1.465 0.043,2.848 0.684,4.012 1.074,1.938 3.234,3.023 5.449,3.023h3.164c2.375,0 4.207,1.328 4.551,3.27 0.039,0.246 0.063,0.488 0.063,0.723 0.004,2.215 -1.789,4.008 -3.996,4.008h-0.004c-2.27,0 -4.473,1.203 -5.398,3.277 -1.98,4.426 1.207,8.723 5.398,8.723h62c3.313,0 6,-2.688 6,-6s-2.688,-6 -6,-6h-10v-20l46,0.129h9.66c3.141,0 6.168,-2.539 6.328,-5.676 0.184,-3.461 -2.57,-6.324 -5.992,-6.324h-0.023,-0.035c-1.555,0 -3.078,-0.508 -4.156,-1.535 -0.34,-0.324 -0.637,-0.699 -0.875,-1.129 -2.574,-4.637 0.711,-9.336 5.094,-9.336z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:gradientRadius="80.322"
|
||||
android:centerX="60.334"
|
||||
android:centerY="65.146"
|
||||
android:type="radial"
|
||||
android:tileMode="mirror">
|
||||
<item android:offset="0" android:color="#1F0FCCFF"/>
|
||||
<item android:offset="0.1927" android:color="#1F0FCEFF"/>
|
||||
<item android:offset="0.7025" android:color="#1F0FD5FF"/>
|
||||
<item android:offset="1" android:color="#1F0FD7FF"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
android:pathData="m18,100v-60h92v60c0,5.523 -4.477,10 -10,10h-72c-5.523,0 -10,-4.477 -10,-10z"
|
||||
android:fillColor="#ffc662"/>
|
||||
<path
|
||||
android:pathData="m18,100v-60h92v60c0,5.523 -4.477,10 -10,10h-72c-5.523,0 -10,-4.477 -10,-10z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startY="110"
|
||||
android:startX="64"
|
||||
android:endY="40"
|
||||
android:endX="64"
|
||||
android:type="linear"
|
||||
android:tileMode="mirror">
|
||||
<item android:offset="0" android:color="#FFFFC662"/>
|
||||
<item android:offset="0.0036" android:color="#FFFFC662"/>
|
||||
<item android:offset="0.6085" android:color="#FFFFC582"/>
|
||||
<item android:offset="1" android:color="#FFFFC491"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
android:pathData="m110,29.602v16.398h-92v-16.398c0,-5.309 4.332,-9.602 9.684,-9.602h72.633c5.352,0 9.684,4.293 9.684,9.602"
|
||||
android:fillColor="#ff634f"/>
|
||||
<path
|
||||
android:pathData="m110,29.602v16.398h-92v-16.398c0,-5.309 4.332,-9.602 9.684,-9.602h72.633c5.352,0 9.684,4.293 9.684,9.602">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startY="46"
|
||||
android:startX="64"
|
||||
android:endY="20"
|
||||
android:endX="64"
|
||||
android:type="linear"
|
||||
android:tileMode="mirror">
|
||||
<item android:offset="0" android:color="#FFFF634D"/>
|
||||
<item android:offset="0.2083" android:color="#FFFD6464"/>
|
||||
<item android:offset="0.5223" android:color="#FFFC6582"/>
|
||||
<item android:offset="0.7935" android:color="#FFFA6694"/>
|
||||
<item android:offset="0.9892" android:color="#FFFA669A"/>
|
||||
<item android:offset="1" android:color="#FFFA669A"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
android:pathData="m43,34c-2.75,0 -5,-2.25 -5,-5v-12c0,-2.75 2.25,-5 5,-5s5,2.25 5,5v12c0,2.75 -2.25,5 -5,5z"
|
||||
android:fillColor="#888"/>
|
||||
<path
|
||||
android:pathData="m49.309,20h-12.621c-2.832,1.988 -4.688,5.277 -4.688,9 0,6.07 4.93,11 11,11 6.07,0 11,-4.93 11,-11 0,-3.723 -1.855,-7.012 -4.691,-9z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startY="40"
|
||||
android:startX="43"
|
||||
android:endY="20"
|
||||
android:endX="43"
|
||||
android:type="linear"
|
||||
android:tileMode="mirror">
|
||||
<item android:offset="0" android:color="#FFFF5840"/>
|
||||
<item android:offset="0.0072" android:color="#FFFF5840"/>
|
||||
<item android:offset="0.9892" android:color="#FFFA528C"/>
|
||||
<item android:offset="1" android:color="#FFFA528C"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
android:pathData="m85,34c-2.75,0 -5,-2.25 -5,-5v-12c0,-2.75 2.25,-5 5,-5s5,2.25 5,5v12c0,2.75 -2.25,5 -5,5z"
|
||||
android:fillColor="#888"/>
|
||||
<path
|
||||
android:pathData="m43,34c-2.75,0 -5,-2.25 -5,-5v-12c0,-2.75 2.25,-5 5,-5s5,2.25 5,5v12c0,2.75 -2.25,5 -5,5z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startY="12"
|
||||
android:startX="43"
|
||||
android:endY="34"
|
||||
android:endX="43"
|
||||
android:type="linear"
|
||||
android:tileMode="mirror">
|
||||
<item android:offset="0" android:color="#FFA4A4A4"/>
|
||||
<item android:offset="0.6301" android:color="#FF7F7F7F"/>
|
||||
<item android:offset="1" android:color="#FF6F6F6F"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:pathData="m91.309,20h-12.621c-2.832,1.988 -4.688,5.277 -4.688,9 0,6.07 4.93,11 11,11 6.07,0 11,-4.93 11,-11 0,-3.723 -1.855,-7.012 -4.691,-9z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startY="40"
|
||||
android:startX="85"
|
||||
android:endY="20"
|
||||
android:endX="85"
|
||||
android:type="linear"
|
||||
android:tileMode="mirror">
|
||||
<item android:offset="0" android:color="#FFFF5840"/>
|
||||
<item android:offset="0.0072" android:color="#FFFF5840"/>
|
||||
<item android:offset="0.9892" android:color="#FFFA528C"/>
|
||||
<item android:offset="1" android:color="#FFFA528C"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:pathData="m85,34c-2.75,0 -5,-2.25 -5,-5v-12c0,-2.75 2.25,-5 5,-5s5,2.25 5,5v12c0,2.75 -2.25,5 -5,5z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startY="12"
|
||||
android:startX="85"
|
||||
android:endY="34"
|
||||
android:endX="85"
|
||||
android:type="linear"
|
||||
android:tileMode="mirror">
|
||||
<item android:offset="0" android:color="#FFA4A4A4"/>
|
||||
<item android:offset="0.6301" android:color="#FF7F7F7F"/>
|
||||
<item android:offset="1" android:color="#FF6F6F6F"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:pathData="m78,81.008c0,2.762 2.238,5 5,4.996h2.992c3.316,-0.008 6.008,2.684 6.008,5.996s-2.688,6 -6,6h-8c-3.313,0 -6,2.688 -6,6s2.688,6 6,6h22c5.523,0 10,-4.477 10,-10v-24l-27.008,0.012c-2.758,-0 -4.992,2.234 -4.992,4.996z"
|
||||
android:fillColor="#ffb86a"/>
|
||||
<path
|
||||
android:pathData="m18,68h17.785c1.992,0 3.84,-1.363 4.16,-3.328 0.406,-2.508 -1.516,-4.672 -3.945,-4.672h-3c-1.656,0 -3,-1.344 -3,-3s1.344,-3 3,-3h14.785c1.992,0 3.84,-1.363 4.16,-3.328 0.406,-2.508 -1.516,-4.672 -3.945,-4.672h-30z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startY="108.25"
|
||||
android:startX="35"
|
||||
android:endY="43.742"
|
||||
android:endX="35"
|
||||
android:type="linear"
|
||||
android:tileMode="mirror">
|
||||
<item android:offset="0" android:color="#FFFFCE76"/>
|
||||
<item android:offset="0.0036" android:color="#FFFFCE76"/>
|
||||
<item android:offset="0.6054" android:color="#FFFFCD92"/>
|
||||
<item android:offset="1" android:color="#FFFFCCA0"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
<path
|
||||
android:pathData="m98,62c0,3.313 -2.688,6 -6,6s-6,-2.688 -6,-6 2.688,-6 6,-6 6,2.688 6,6z"
|
||||
android:fillColor="#ffb977"/>
|
||||
<path
|
||||
android:pathData="m48,74h-8c-2.211,0 -4,-1.789 -4,-4v-8c0,-2.211 1.789,-4 4,-4h8c2.211,0 4,1.789 4,4v8c0,2.211 -1.789,4 -4,4zM72,70v-8c0,-2.211 -1.789,-4 -4,-4h-8c-2.211,0 -4,1.789 -4,4v8c0,2.211 1.789,4 4,4h8c2.211,0 4,-1.789 4,-4zM92,70v-8c0,-2.211 -1.789,-4 -4,-4h-8c-2.211,0 -4,1.789 -4,4v8c0,2.211 1.789,4 4,4h8c2.211,0 4,-1.789 4,-4zM52,90v-8c0,-2.211 -1.789,-4 -4,-4h-8c-2.211,0 -4,1.789 -4,4v8c0,2.211 1.789,4 4,4h8c2.211,0 4,-1.789 4,-4zM72,90v-8c0,-2.211 -1.789,-4 -4,-4h-8c-2.211,0 -4,1.789 -4,4v8c0,2.211 1.789,4 4,4h8c2.211,0 4,-1.789 4,-4zM92,90v-8c0,-2.211 -1.789,-4 -4,-4h-8c-2.211,0 -4,1.789 -4,4v8c0,2.211 1.789,4 4,4h8c2.211,0 4,-1.789 4,-4z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startY="94"
|
||||
android:startX="64"
|
||||
android:endY="58"
|
||||
android:endX="64"
|
||||
android:type="linear"
|
||||
android:tileMode="mirror">
|
||||
<item android:offset="0" android:color="#FFFFE79F"/>
|
||||
<item android:offset="0.1186" android:color="#FFFFE9A6"/>
|
||||
<item android:offset="1" android:color="#FFFFF5D5"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
android:pathData="m48,74h-8c-2.211,0 -4,-1.789 -4,-4v-8c0,-2.211 1.789,-4 4,-4h8c2.211,0 4,1.789 4,4v8c0,2.211 -1.789,4 -4,4zM72,70v-8c0,-2.211 -1.789,-4 -4,-4h-8c-2.211,0 -4,1.789 -4,4v8c0,2.211 1.789,4 4,4h8c2.211,0 4,-1.789 4,-4zM92,70v-8c0,-2.211 -1.789,-4 -4,-4h-8c-2.211,0 -4,1.789 -4,4v8c0,2.211 1.789,4 4,4h8c2.211,0 4,-1.789 4,-4zM52,90v-8c0,-2.211 -1.789,-4 -4,-4h-8c-2.211,0 -4,1.789 -4,4v8c0,2.211 1.789,4 4,4h8c2.211,0 4,-1.789 4,-4zM72,90v-8c0,-2.211 -1.789,-4 -4,-4h-8c-2.211,0 -4,1.789 -4,4v8c0,2.211 1.789,4 4,4h8c2.211,0 4,-1.789 4,-4zM92,90v-8c0,-2.211 -1.789,-4 -4,-4h-8c-2.211,0 -4,1.789 -4,4v8c0,2.211 1.789,4 4,4h8c2.211,0 4,-1.789 4,-4z"
|
||||
android:fillColor="#ffe79f"/>
|
||||
<path
|
||||
android:pathData="m124,104c0,11.047 -8.953,20 -20,20 -11.047,0 -20,-8.953 -20,-20 0,-11.047 8.953,-20 20,-20 11.047,0 20,8.953 20,20z"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="m104,80c-13.254,0 -24,10.746 -24,24 0,13.254 10.746,24 24,24 13.254,0 24,-10.746 24,-24 0,-13.254 -10.746,-24 -24,-24zM104,120c-8.836,0 -16,-7.164 -16,-16 0,-8.836 7.164,-16 16,-16 8.836,0 16,7.164 16,16 0,8.836 -7.164,16 -16,16z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startY="128"
|
||||
android:startX="104"
|
||||
android:endY="80"
|
||||
android:endX="104"
|
||||
android:type="linear"
|
||||
android:tileMode="mirror">
|
||||
<item android:offset="0" android:color="#FF155CDE"/>
|
||||
<item android:offset="0.6248" android:color="#FF2289E7"/>
|
||||
<item android:offset="1" android:color="#FF289FEC"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
android:pathData="m104,80c-13.254,0 -24,10.746 -24,24 0,13.254 10.746,24 24,24 13.254,0 24,-10.746 24,-24 0,-13.254 -10.746,-24 -24,-24zM104,120c-8.836,0 -16,-7.164 -16,-16 0,-8.836 7.164,-16 16,-16 8.836,0 16,7.164 16,16 0,8.836 -7.164,16 -16,16z"
|
||||
android:fillColor="#1f80e5"/>
|
||||
<path
|
||||
android:pathData="m113.41,110.59 l-5.563,-5.563c0.086,-0.328 0.148,-0.668 0.148,-1.023 0,-1.477 -0.809,-2.754 -2,-3.445v-6.555c0,-1.105 -0.895,-2 -2,-2s-2,0.895 -2,2v6.555c-1.191,0.691 -2,1.969 -2,3.445 0,2.211 1.789,4 4,4 0.355,0 0.695,-0.063 1.023,-0.148l5.563,5.563c0.391,0.391 0.902,0.586 1.414,0.586s1.023,-0.195 1.414,-0.586c0.781,-0.781 0.781,-2.047 0,-2.828z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:startY="92"
|
||||
android:startX="107"
|
||||
android:endY="114"
|
||||
android:endX="107"
|
||||
android:type="linear"
|
||||
android:tileMode="mirror">
|
||||
<item android:offset="0" android:color="#FF919191"/>
|
||||
<item android:offset="1" android:color="#FF6F6F6F"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
android:pathData="m113.41,110.59 l-5.563,-5.563c0.086,-0.328 0.148,-0.668 0.148,-1.023 0,-1.477 -0.809,-2.754 -2,-3.445v-6.555c0,-1.105 -0.895,-2 -2,-2s-2,0.895 -2,2v6.555c-1.191,0.691 -2,1.969 -2,3.445 0,2.211 1.789,4 4,4 0.355,0 0.695,-0.063 1.023,-0.148l5.563,5.563c0.391,0.391 0.902,0.586 1.414,0.586s1.023,-0.195 1.414,-0.586c0.781,-0.781 0.781,-2.047 0,-2.828z"
|
||||
android:fillColor="#919191"/>
|
||||
</vector>
|
||||
|
10
app/src/main/res/drawable/unread_red_circle.xml
Normal file
10
app/src/main/res/drawable/unread_red_circle.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) Kacper Ziubryniewicz 2019-11-23
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="oval">
|
||||
<solid android:color="@color/red500"/>
|
||||
<size android:width="10dp" android:height="10dp"/>
|
||||
</shape>
|
@ -4,11 +4,17 @@
|
||||
-->
|
||||
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
android:padding="24dp">
|
||||
@ -46,41 +52,63 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:hint="@string/dialog_event_manual_team">
|
||||
|
||||
<pl.szczodrzynski.edziennik.utils.TextInputDropDown
|
||||
android:id="@+id/teamDropdown"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:enabled="false"
|
||||
tools:text="2b3T"/>
|
||||
tools:text="2b3T" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
|
||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||
android:id="@+id/shareSwitch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/dialog_event_manual_share_enabled" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/shareDetails"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/dialog_event_manual_share_first_notice"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:hint="@string/dialog_event_manual_subject">
|
||||
<pl.szczodrzynski.edziennik.utils.TextInputDropDown
|
||||
android:id="@+id/subjectDropdown"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:enabled="false"
|
||||
tools:text="2b3T"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
android:baselineAligned="false"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:hint="@string/dialog_event_manual_teacher">
|
||||
<pl.szczodrzynski.edziennik.utils.TextInputDropDown
|
||||
android:id="@+id/teacherDropdown"
|
||||
android:layout_width="match_parent"
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:enabled="false"
|
||||
tools:text="2b3T"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
android:layout_weight="1"
|
||||
android:hint="@string/dialog_event_manual_type">
|
||||
|
||||
<pl.szczodrzynski.edziennik.utils.TextInputDropDown
|
||||
android:id="@+id/typeDropdown"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:enabled="false"
|
||||
tools:text="2b3T" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/typeColor"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginTop="2dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:background="@drawable/bg_circle"
|
||||
android:foreground="?selectableItemBackgroundBorderless" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
|
||||
@ -89,7 +117,7 @@
|
||||
android:layout_marginTop="8dp"
|
||||
android:hint="@string/dialog_event_manual_topic">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
<pl.szczodrzynski.edziennik.utils.TextInputKeyboardEdit
|
||||
android:id="@+id/topic"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@ -98,5 +126,64 @@
|
||||
tools:text="2b3T" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.mikepenz.iconics.view.IconicsCheckableTextView
|
||||
android:id="@+id/showMore"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp"
|
||||
android:text="@string/dialog_event_manual_more_options"
|
||||
android:background="?selectableItemBackground"
|
||||
|
||||
app:iiv_end_icon="cmd-chevron-down"
|
||||
app:iiv_end_color="?android:textColorSecondary"
|
||||
app:iiv_end_size="16dp"
|
||||
|
||||
app:iiv_end_checked_icon="cmd-chevron-up"
|
||||
app:iiv_end_checked_color="?android:textColorSecondary"
|
||||
app:iiv_end_checked_size="16dp"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/moreLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:hint="@string/dialog_event_manual_subject">
|
||||
|
||||
<pl.szczodrzynski.edziennik.utils.TextInputDropDown
|
||||
android:id="@+id/subjectDropdown"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:enabled="false"
|
||||
tools:text="2b3T" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:hint="@string/dialog_event_manual_teacher">
|
||||
|
||||
<pl.szczodrzynski.edziennik.utils.TextInputDropDown
|
||||
android:id="@+id/teacherDropdown"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:enabled="false"
|
||||
tools:text="2b3T" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
</layout>
|
||||
|
@ -21,217 +21,207 @@
|
||||
<variable name="oldTeamName" type="String" />
|
||||
<variable name="teamName" type="String" />
|
||||
</data>
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="24dp">
|
||||
|
||||
android:layout_height="match_parent">
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:baselineAligned="false">
|
||||
android:padding="24dp">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_weight="1">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{oldSubjectName}"
|
||||
android:textIsSelectable="true"
|
||||
android:textAppearance="@style/NavView.TextView.Medium"
|
||||
android:textColor="?android:textColorTertiary"
|
||||
android:visibility="@{oldSubjectName == null ? View.GONE : View.VISIBLE}"
|
||||
app:strikeThrough="@{true}"
|
||||
tools:text="pracownia urządzeń techniki komputerowej" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{subjectName}"
|
||||
android:textIsSelectable="true"
|
||||
android:textAppearance="@style/NavView.TextView.Title"
|
||||
android:visibility="@{subjectName == null ? View.GONE : View.VISIBLE}"
|
||||
tools:text="pracownia urządzeń techniki komputerowej" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/lessonDate"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textIsSelectable="true"
|
||||
android:textAppearance="@style/NavView.TextView.Subtitle"
|
||||
tools:text="czwartek, 14 listopada 2019"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/NavView.TextView.Helper"
|
||||
android:text="@string/dialog_lesson_details_number"
|
||||
android:visibility="@{lesson.displayLessonNumber == null ? View.GONE : View.VISIBLE}"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:text="@{lesson.displayLessonNumber.toString()}"
|
||||
android:textSize="36sp"
|
||||
android:visibility="@{lesson.displayLessonNumber == null ? View.GONE : View.VISIBLE}"
|
||||
tools:text="4" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{lesson.displayStartTime.stringHM + ` - ` + lesson.displayEndTime.stringHM}"
|
||||
tools:text="14:55 - 15:40" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/shiftedLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:baselineAligned="false"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/shiftedText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="italic"
|
||||
tools:text="Lekcja przeniesiona na czwartek, 17 października" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/shiftedGoTo"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Przejdź" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textAppearance="@style/NavView.TextView.Helper"
|
||||
android:text="@string/dialog_lesson_details_teacher"
|
||||
android:visibility="@{teacherName != null || oldTeacherName != null ? View.VISIBLE : View.GONE}"/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/NavView.TextView.Helper"
|
||||
android:text="@{oldTeacherName}"
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="@{oldTeacherName != null ? View.VISIBLE : View.GONE}"
|
||||
app:strikeThrough="@{true}"
|
||||
tools:text="Janósz Kowalski" />
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{teacherName}"
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="@{teacherName != null ? View.VISIBLE : View.GONE}"
|
||||
tools:text="Janósz Kowalski" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textAppearance="@style/NavView.TextView.Helper"
|
||||
android:text="@string/dialog_lesson_details_classroom"
|
||||
android:visibility="@{classroom != null || oldClassroom != null ? View.VISIBLE : View.GONE}"/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/NavView.TextView.Helper"
|
||||
android:text="@{oldClassroom}"
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="@{oldClassroom != null ? View.VISIBLE : View.GONE}"
|
||||
app:strikeThrough="@{true}"
|
||||
tools:text="013 informatyczna" />
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{classroom}"
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="@{classroom != null ? View.VISIBLE : View.GONE}"
|
||||
tools:text="013 informatyczna" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textAppearance="@style/NavView.TextView.Helper"
|
||||
android:text="@string/dialog_lesson_details_team"
|
||||
android:visibility="@{teamName != null || oldTeamName != null ? View.VISIBLE : View.GONE}"/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/NavView.TextView.Helper"
|
||||
android:text="@{oldTeamName}"
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="@{oldTeamName != null ? View.VISIBLE : View.GONE}"
|
||||
app:strikeThrough="@{true}"
|
||||
tools:text="013 informatyczna" />
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{teamName}"
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="@{teamName != null ? View.VISIBLE : View.GONE}"
|
||||
tools:text="013 informatyczna" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textAppearance="@style/NavView.TextView.Helper"
|
||||
android:visibility="@{App.devMode ? View.VISIBLE : View.GONE}"
|
||||
android:text="@string/dialog_lesson_details_id" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="0dp"
|
||||
android:text="@{Long.toString(lesson.id)}"
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="@{App.devMode ? View.VISIBLE : View.GONE}"
|
||||
tools:text="12345" />
|
||||
|
||||
<!--<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/gradeHistoryNest"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="@{historyVisible ? View.VISIBLE : View.GONE}">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/gradeHistoryList"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:listitem="@layout/row_grades_list_item" />
|
||||
android:orientation="horizontal"
|
||||
android:baselineAligned="false">
|
||||
|
||||
</androidx.core.widget.NestedScrollView>-->
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_weight="1">
|
||||
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{oldSubjectName}"
|
||||
android:textIsSelectable="true"
|
||||
android:textAppearance="@style/NavView.TextView.Medium"
|
||||
android:textColor="?android:textColorTertiary"
|
||||
android:visibility="@{oldSubjectName == null ? View.GONE : View.VISIBLE}"
|
||||
app:strikeThrough="@{true}"
|
||||
tools:text="pracownia urządzeń techniki komputerowej" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{subjectName}"
|
||||
android:textIsSelectable="true"
|
||||
android:textAppearance="@style/NavView.TextView.Title"
|
||||
android:visibility="@{subjectName == null ? View.GONE : View.VISIBLE}"
|
||||
tools:text="pracownia urządzeń techniki komputerowej" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/lessonDate"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textIsSelectable="true"
|
||||
android:textAppearance="@style/NavView.TextView.Subtitle"
|
||||
tools:text="czwartek, 14 listopada 2019"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:gravity="center">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/NavView.TextView.Helper"
|
||||
android:text="@string/dialog_lesson_details_number"
|
||||
android:visibility="@{lesson.displayLessonNumber == null ? View.GONE : View.VISIBLE}"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:text="@{lesson.displayLessonNumber.toString()}"
|
||||
android:textSize="36sp"
|
||||
android:visibility="@{lesson.displayLessonNumber == null ? View.GONE : View.VISIBLE}"
|
||||
tools:text="4" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{lesson.displayStartTime.stringHM + ` - ` + lesson.displayEndTime.stringHM}"
|
||||
tools:text="14:55 - 15:40" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/shiftedLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:baselineAligned="false"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/shiftedText"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="italic"
|
||||
tools:text="Lekcja przeniesiona na czwartek, 17 października" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/shiftedGoTo"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Przejdź" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textAppearance="@style/NavView.TextView.Helper"
|
||||
android:text="@string/dialog_lesson_details_teacher"
|
||||
android:visibility="@{teacherName != null || oldTeacherName != null ? View.VISIBLE : View.GONE}"/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/NavView.TextView.Helper"
|
||||
android:text="@{oldTeacherName}"
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="@{oldTeacherName != null ? View.VISIBLE : View.GONE}"
|
||||
app:strikeThrough="@{true}"
|
||||
tools:text="Janósz Kowalski" />
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{teacherName}"
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="@{teacherName != null ? View.VISIBLE : View.GONE}"
|
||||
tools:text="Janósz Kowalski" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textAppearance="@style/NavView.TextView.Helper"
|
||||
android:text="@string/dialog_lesson_details_classroom"
|
||||
android:visibility="@{classroom != null || oldClassroom != null ? View.VISIBLE : View.GONE}"/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/NavView.TextView.Helper"
|
||||
android:text="@{oldClassroom}"
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="@{oldClassroom != null ? View.VISIBLE : View.GONE}"
|
||||
app:strikeThrough="@{true}"
|
||||
tools:text="013 informatyczna" />
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{classroom}"
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="@{classroom != null ? View.VISIBLE : View.GONE}"
|
||||
tools:text="013 informatyczna" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textAppearance="@style/NavView.TextView.Helper"
|
||||
android:text="@string/dialog_lesson_details_team"
|
||||
android:visibility="@{teamName != null || oldTeamName != null ? View.VISIBLE : View.GONE}"/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/NavView.TextView.Helper"
|
||||
android:text="@{oldTeamName}"
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="@{oldTeamName != null ? View.VISIBLE : View.GONE}"
|
||||
app:strikeThrough="@{true}"
|
||||
tools:text="013 informatyczna" />
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{teamName}"
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="@{teamName != null ? View.VISIBLE : View.GONE}"
|
||||
tools:text="013 informatyczna" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textAppearance="@style/NavView.TextView.Helper"
|
||||
android:visibility="@{App.devMode ? View.VISIBLE : View.GONE}"
|
||||
android:text="@string/dialog_lesson_details_id" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="0dp"
|
||||
android:text="@{Long.toString(lesson.id)}"
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="@{App.devMode ? View.VISIBLE : View.GONE}"
|
||||
tools:text="12345" />
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
</layout>
|
||||
|
@ -1,35 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/notificationsView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
android:layout_height="match_parent"
|
||||
tools:listitem="@layout/row_notifications_item"
|
||||
tools:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/notificationsNoData"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_gravity="center"
|
||||
android:drawableTop="@drawable/ic_no_notifications"
|
||||
android:drawablePadding="16dp"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:text="@string/notifications_no_data"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="italic"
|
||||
android:textSize="24sp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
tools:visibility="visible" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</FrameLayout>
|
||||
</layout>
|
@ -2,89 +2,96 @@
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<FrameLayout
|
||||
|
||||
<pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoIndicator
|
||||
android:id="@+id/refreshLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/timetableLayout"
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:visibility="gone">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?colorSurface"
|
||||
style="@style/Widget.MaterialComponents.AppBarLayout.Surface">
|
||||
|
||||
<com.nshmura.recyclertablayout.RecyclerTabLayout
|
||||
android:id="@+id/tabLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:background="@color/colorSurface_6dp"
|
||||
app:rtl_tabTextAppearance="@style/rtl_RecyclerTabLayout.Tab"
|
||||
app:rtl_tabIndicatorColor="?colorPrimary"
|
||||
app:rtl_tabMinWidth="90dp"
|
||||
app:rtl_tabMaxWidth="300dp"
|
||||
app:rtl_tabSelectedTextColor="?colorPrimary"
|
||||
app:rtl_tabPaddingStart="16dp"
|
||||
app:rtl_tabPaddingEnd="16dp"
|
||||
app:rtl_tabPaddingTop="12dp"
|
||||
app:rtl_tabPaddingBottom="12dp"/>
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
android:id="@+id/viewPager"
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/timetableLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
tools:visibility="gone">
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
style="@style/Widget.MaterialComponents.AppBarLayout.Surface"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?colorSurface">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/timetableNotPublicLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
android:gravity="center"
|
||||
tools:visibility="visible">
|
||||
<com.nshmura.recyclertablayout.RecyclerTabLayout
|
||||
android:id="@+id/tabLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:background="@color/colorSurface_6dp"
|
||||
app:rtl_tabIndicatorColor="?colorPrimary"
|
||||
app:rtl_tabMaxWidth="300dp"
|
||||
app:rtl_tabMinWidth="90dp"
|
||||
app:rtl_tabPaddingBottom="12dp"
|
||||
app:rtl_tabPaddingEnd="16dp"
|
||||
app:rtl_tabPaddingStart="16dp"
|
||||
app:rtl_tabPaddingTop="12dp"
|
||||
app:rtl_tabSelectedTextColor="?colorPrimary"
|
||||
app:rtl_tabTextAppearance="@style/rtl_RecyclerTabLayout.Tab" />
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/ic_no_timetable" />
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
android:id="@+id/viewPager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:text="@string/timetable_not_public_title"
|
||||
android:textSize="24sp" />
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
<LinearLayout
|
||||
android:id="@+id/timetableNotPublicLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:text="@string/timetable_not_public_text"
|
||||
android:textSize="16sp" />
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/timetable_not_public_hint"
|
||||
android:textSize="14sp" />
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/ic_no_timetable" />
|
||||
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:text="@string/timetable_not_public_title"
|
||||
android:textSize="24sp" />
|
||||
|
||||
</FrameLayout>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/timetable_not_public_text"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/timetable_not_public_hint"
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
</pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoIndicator>
|
||||
</layout>
|
@ -28,126 +28,5 @@
|
||||
tools:visibility="gone"/>
|
||||
</ScrollView>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/noLessonsLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
android:gravity="center"
|
||||
tools:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/ic_timetable" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:text="@string/timetable_no_lessons_title"
|
||||
android:textSize="24sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/freeDayLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
android:gravity="center"
|
||||
tools:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/ic_sunbed" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:text="@string/timetable_free_day_title"
|
||||
android:textSize="24sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/timetable_free_day_text"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/freeDayText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:gravity="center"
|
||||
tools:text="Dzień wolny dla szkoły z puli dyrektorskiej z okazji obchodów Światowego Dnia Wtorku w mieście Poznań i na przedmieśiach"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/freeDayShowTimetable"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/timetable_free_day_show" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/noTimetableLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
android:gravity="center"
|
||||
tools:visibility="visible">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/ic_sync" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:text="@string/timetable_no_timetable_title"
|
||||
android:textSize="24sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/timetable_no_timetable_text"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/noTimetableSync"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/timetable_no_timetable_sync" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/noTimetableWeek"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="@string/timetable_no_timetable_week"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="italic"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
</layout>
|
@ -1,75 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:padding="8dp"
|
||||
android:background="?selectableItemBackground">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/notificationsItemCard"
|
||||
android:layout_width="match_parent"
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:background="?selectableItemBackground"
|
||||
app:cardElevation="4dp"
|
||||
app:cardCornerRadius="5dp"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingRight="10dp"
|
||||
android:paddingBottom="3dp">
|
||||
android:textAppearance="@style/NavView.TextView.Medium"
|
||||
tools:text="Dzisiaj 1 to szczęśliwy numerek" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?selectableItemBackground"
|
||||
android:orientation="vertical"
|
||||
android:padding="8dp">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/notificationsItemDate"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:textSize="16sp"
|
||||
tools:text="date" />
|
||||
<TextView
|
||||
android:id="@+id/profileDate"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
tools:text="Władca Androida • 22 listopada" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/notificationsItemText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="18sp"
|
||||
android:autoLink="all"
|
||||
tools:text="text" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/notificationsItemTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:textAppearance="@style/Base.TextAppearance.AppCompat.Small"
|
||||
tools:text="title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/notificationsItemType"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/Base.TextAppearance.AppCompat.Small"
|
||||
tools:text="type" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
<TextView
|
||||
android:id="@+id/type"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="Szczęśliwy numerek" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
47
app/src/main/res/layout/timetable_free_day.xml
Normal file
47
app/src/main/res/layout/timetable_free_day.xml
Normal file
@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) Kuba Szczodrzyński 2019-11-15.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/freeDayLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableTop="@drawable/ic_sunbed"
|
||||
android:drawablePadding="16dp"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:text="@string/timetable_free_day_title"
|
||||
android:textSize="24sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/timetable_free_day_text"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/freeDayText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:gravity="center"
|
||||
android:textSize="16sp"
|
||||
tools:text="Dzień wolny dla szkoły z puli dyrektorskiej z okazji obchodów Światowego Dnia Wtorku w mieście Poznań i na przedmieśiach" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/freeDayShowTimetable"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/timetable_free_day_show" />
|
||||
|
||||
</LinearLayout>
|
@ -11,6 +11,9 @@
|
||||
<variable
|
||||
name="lessonNumber"
|
||||
type="Integer" />
|
||||
<variable
|
||||
name="unread"
|
||||
type="boolean" />
|
||||
</data>
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
@ -70,6 +73,17 @@
|
||||
tools:maxLines="2"
|
||||
tools:text="pracownia urządzeń techniki komputerowej" />
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingRight="8dp"
|
||||
android:visibility="@{unread ? View.VISIBLE : View.GONE}"
|
||||
app:srcCompat="@drawable/unread_red_circle" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/attendanceIcon"
|
||||
android:layout_width="24dp"
|
||||
@ -136,4 +150,4 @@
|
||||
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
</layout>
|
||||
</layout>
|
||||
|
14
app/src/main/res/layout/timetable_no_lessons.xml
Normal file
14
app/src/main/res/layout/timetable_no_lessons.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) Kuba Szczodrzyński 2019-11-15.
|
||||
-->
|
||||
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:drawableTop="@drawable/ic_timetable"
|
||||
android:drawablePadding="16dp"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:text="@string/timetable_no_lessons_title"
|
||||
android:textSize="24sp" />
|
50
app/src/main/res/layout/timetable_no_timetable.xml
Normal file
50
app/src/main/res/layout/timetable_no_timetable.xml
Normal file
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (c) Kuba Szczodrzyński 2019-11-15.
|
||||
-->
|
||||
|
||||
<layout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/noTimetableLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableTop="@drawable/ic_sync"
|
||||
android:drawablePadding="16dp"
|
||||
android:fontFamily="sans-serif-light"
|
||||
android:text="@string/timetable_no_timetable_title"
|
||||
android:textSize="24sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/timetable_no_timetable_text"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/noTimetableSync"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/timetable_no_timetable_sync" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/noTimetableWeek"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="12sp"
|
||||
android:textStyle="italic"
|
||||
tools:text="@string/timetable_no_timetable_week" />
|
||||
|
||||
</LinearLayout>
|
||||
</layout>
|
@ -547,7 +547,7 @@
|
||||
<string name="settings_about_licenses_text">Open-source licenses</string>
|
||||
<string name="settings_about_privacy_policy_text">Privacy policy</string>
|
||||
<string name="settings_about_register_title_text">E-register</string>
|
||||
<string name="settings_about_title_subtext">© Kuba Szczodrzyński September 2018 - October 2019</string>
|
||||
<string name="settings_about_title_subtext">© Kuba Szczodrzyński && Kacper Ziubryniewicz\nSeptember 2018 - November 2019</string>
|
||||
<string name="settings_about_update_subtext">Click to check for updates</string>
|
||||
<string name="settings_about_update_text">Update</string>
|
||||
<string name="settings_about_version_text">Version</string>
|
||||
|
@ -72,6 +72,12 @@
|
||||
<string name="error_173" translatable="false">ERROR_LOGIN_LIBRUS_PORTAL_REFRESH_REVOKED</string>
|
||||
<string name="error_174" translatable="false">ERROR_LIBRUS_SYNERGIA_OTHER</string>
|
||||
<string name="error_175" translatable="false">ERROR_LIBRUS_SYNERGIA_MAINTENANCE</string>
|
||||
<string name="error_176" translatable="false">ERROR_LIBRUS_MESSAGES_MAINTENANCE</string>
|
||||
<string name="error_177" translatable="false">ERROR_LIBRUS_MESSAGES_ERROR</string>
|
||||
<string name="error_178" translatable="false">ERROR_LIBRUS_MESSAGES_OTHER</string>
|
||||
<string name="error_179" translatable="false">ERROR_LOGIN_LIBRUS_MESSAGES_INVALID_LOGIN</string>
|
||||
<string name="error_180" translatable="false">ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN</string>
|
||||
<string name="error_181" translatable="false">ERROR_LIBRUS_API_MAINTENANCE</string>
|
||||
|
||||
<string name="error_201" translatable="false">ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_LOGIN</string>
|
||||
<string name="error_202" translatable="false">ERROR_LOGIN_MOBIDZIENNIK_WEB_OLD_PASSWORD</string>
|
||||
@ -165,7 +171,7 @@
|
||||
<string name="error_127_reason">Wymagana akceptacja regulaminu</string>
|
||||
<string name="error_128_reason">Błąd zmiany hasła</string>
|
||||
<string name="error_129_reason">Wymagana zmiana hasła</string>
|
||||
<string name="error_130_reason">Nieprawidłowe dane logowania</string>
|
||||
<string name="error_130_reason">Librus API: nieprawidłowe dane logowania</string>
|
||||
<string name="error_131_reason">Inny błąd logowania do API</string>
|
||||
<string name="error_132_reason">Brak tokenu CSRF</string>
|
||||
<string name="error_133_reason">Konto LIBRUS nie zostało aktywowane</string>
|
||||
@ -206,7 +212,13 @@
|
||||
<string name="error_172_reason">ERROR_LOGIN_LIBRUS_PORTAL_REFRESH_INVALID</string>
|
||||
<string name="error_173_reason">ERROR_LOGIN_LIBRUS_PORTAL_REFRESH_REVOKED</string>
|
||||
<string name="error_174_reason">ERROR_LIBRUS_SYNERGIA_OTHER</string>
|
||||
<string name="error_175_reason">ERROR_LIBRUS_SYNERGIA_MAINTENANCE</string>
|
||||
<string name="error_175_reason">Librus Synergia: przerwa techniczna</string>
|
||||
<string name="error_176_reason">Librus Wiadomości: przerwa techniczna</string>
|
||||
<string name="error_177_reason">ERROR_LIBRUS_MESSAGES_ERROR</string>
|
||||
<string name="error_178_reason">ERROR_LIBRUS_MESSAGES_OTHER</string>
|
||||
<string name="error_179_reason">Librus Wiadomości: nieprawidłowe dane logowania</string>
|
||||
<string name="error_180_reason">Librus Portal: nieprawidłowe dane logowania</string>
|
||||
<string name="error_181_reason">Librus API: przerwa techniczna</string>
|
||||
|
||||
<string name="error_201_reason">ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_LOGIN</string>
|
||||
<string name="error_202_reason">ERROR_LOGIN_MOBIDZIENNIK_WEB_OLD_PASSWORD</string>
|
||||
|
@ -593,7 +593,7 @@
|
||||
<string name="settings_about_licenses_text">Licencje open-source</string>
|
||||
<string name="settings_about_privacy_policy_text">Polityka prywatności</string>
|
||||
<string name="settings_about_register_title_text">E-dziennik</string>
|
||||
<string name="settings_about_title_subtext">© Kuba Szczodrzyński wrzesień 2018 - październik 2019</string>
|
||||
<string name="settings_about_title_subtext">© Kuba Szczodrzyński && Kacper Ziubryniewicz\nwrzesień 2018 - listopad 2019</string>
|
||||
<string name="settings_about_update_subtext">Kliknij, aby sprawdzić aktualizacje</string>
|
||||
<string name="settings_about_update_text">Aktualizacja</string>
|
||||
<string name="settings_about_version_text">Wersja</string>
|
||||
@ -1026,4 +1026,9 @@
|
||||
<string name="snackbar_error_text">Wystąpił błąd</string>
|
||||
<string name="dialog_sync_view_list_title">Synchronizacja ręczna</string>
|
||||
<string name="timetable_no_subject_name">(brak nazwy)</string>
|
||||
<string name="dialog_event_manual_more_options">Więcej opcji</string>
|
||||
<string name="edziennik_progress_endpoint_grade_comments">Pobieranie komentarzy ocen...</string>
|
||||
<string name="menu_remove_notifications">Usuń wszystkie</string>
|
||||
<string name="menu_remove_notifications_success">Wyczyszczono powiadomienia</string>
|
||||
<string name="timetable_select_day">Wybierz dzień</string>
|
||||
</resources>
|
||||
|
@ -101,6 +101,8 @@
|
||||
<item name="timetable_lesson_change_color">#ffb300</item>
|
||||
<item name="timetable_lesson_shifted_source_color">#A1887F</item>
|
||||
<item name="timetable_lesson_shifted_target_color">#4caf50</item>
|
||||
<item name="hourDividerColor">#b0b0b0</item>
|
||||
<item name="halfHourDividerColor">#e0e0e0</item>
|
||||
</style>
|
||||
<style name="AppTheme.Dark" parent="NavView.Dark">
|
||||
<item name="colorPrimary">#64b5f6</item>
|
||||
@ -131,6 +133,8 @@
|
||||
<item name="timetable_lesson_change_color">#ffb300</item>
|
||||
<item name="timetable_lesson_shifted_source_color">#A1887F</item>
|
||||
<item name="timetable_lesson_shifted_target_color">#4caf50</item>
|
||||
<item name="hourDividerColor">#7fffffff</item>
|
||||
<item name="halfHourDividerColor">#40ffffff</item>
|
||||
</style>
|
||||
|
||||
|
||||
|
@ -5,8 +5,8 @@ buildscript {
|
||||
kotlin_version = '1.3.50'
|
||||
|
||||
release = [
|
||||
versionName: "3.9.6-dev",
|
||||
versionCode: 3090600
|
||||
versionName: "3.9.10-dev",
|
||||
versionCode: 3091000
|
||||
]
|
||||
|
||||
setup = [
|
||||
@ -59,7 +59,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.5.1'
|
||||
classpath 'com.android.tools.build:gradle:3.5.2'
|
||||
classpath 'me.tatarka:gradle-retrolambda:3.7.0'
|
||||
classpath 'com.google.gms:google-services:4.3.1'
|
||||
classpath 'io.fabric.tools:gradle:1.28.1'
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
|
@ -1,4 +1,4 @@
|
||||
include ':app', ':agendacalendarview', ':mhttp', ':material-about-library', ':cafebar', ':szkolny-font', ':nachos'
|
||||
include ':app', ':agendacalendarview', ':mhttp', ':material-about-library', ':cafebar', ':szkolny-font', ':nachos', ':community-material'
|
||||
/*
|
||||
include ':Navigation'
|
||||
project(':Navigation').projectDir = new File(settingsDir, '../Navigation/navlib')*/
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 Mike Penz
|
||||
* Copyright 2019 Mike Penz
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -26,8 +26,8 @@ android {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
consumerProguardFiles 'consumer-proguard-rules.pro'
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
versionCode 11
|
||||
versionName "1.1"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
@ -47,5 +47,5 @@ if (project.hasProperty('pushall') || project.hasProperty('SzkolnyFontonly')) {
|
||||
|
||||
dependencies {
|
||||
implementation "com.mikepenz:iconics-core:${iconics}"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 Mike Penz
|
||||
* Copyright 2015 Haruki Hasegawa
|
||||
* Copyright 2019 Mike Penz
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -19,21 +18,18 @@ package com.mikepenz.iconics.typeface.library.szkolny.font
|
||||
import com.mikepenz.iconics.typeface.IIcon
|
||||
import com.mikepenz.iconics.typeface.ITypeface
|
||||
import com.mikepenz.iconics.typeface.library.szkolny.R
|
||||
import java.util.LinkedList
|
||||
import java.util.*
|
||||
|
||||
@Suppress("EnumEntryName")
|
||||
object SzkolnyFont : ITypeface {
|
||||
|
||||
override val fontRes: Int
|
||||
get() = R.font.szkolny_font_font_v1_0
|
||||
get() = R.font.szkolny_font_font_v1_1
|
||||
|
||||
override val characters: Map<String, Char> by lazy {
|
||||
mutableMapOf<String, Char>().apply {
|
||||
SzkolnyFont.Icon.values().associateTo(this) { it.name to it.character }
|
||||
//Icon2.values().associateTo(this) { it.name to it.character }
|
||||
}
|
||||
Icon.values().associate { it.name to it.character }
|
||||
}
|
||||
|
||||
|
||||
override val mappingPrefix: String
|
||||
get() = "szf"
|
||||
|
||||
@ -41,7 +37,7 @@ object SzkolnyFont : ITypeface {
|
||||
get() = "Szkolny Font"
|
||||
|
||||
override val version: String
|
||||
get() = "1.0"
|
||||
get() = "1.1"
|
||||
|
||||
override val iconCount: Int
|
||||
get() = characters.size
|
||||
@ -64,17 +60,28 @@ object SzkolnyFont : ITypeface {
|
||||
override val licenseUrl: String
|
||||
get() = ""
|
||||
|
||||
override fun getIcon(key: String): IIcon {
|
||||
return SzkolnyFont.Icon.valueOf(key)
|
||||
}
|
||||
override fun getIcon(key: String): IIcon = Icon.valueOf(key)
|
||||
|
||||
enum class Icon constructor(override val character: Char) : IIcon {
|
||||
szf_eye_check('\ue800'),
|
||||
szf_calendar_off('\ue801'),
|
||||
szf_file_document_edit('\ue802'),
|
||||
szf_message_off('\ue803'),
|
||||
szf_numeric_0_box_multiple_outline_off('\ue804');
|
||||
szf_alarm_bell_outline('\ue800'),
|
||||
szf_calendar_plus_outline('\ue801'),
|
||||
szf_calendar_today_outline('\ue802'),
|
||||
szf_clipboard_list_outline('\ue803'),
|
||||
szf_delete_empty_outline('\ue804'),
|
||||
szf_discord_outline('\ue805'),
|
||||
szf_file_code_outline('\ue806'),
|
||||
szf_file_excel_outline('\ue807'),
|
||||
szf_file_image_outline('\ue808'),
|
||||
szf_file_music_outline('\ue809'),
|
||||
szf_file_pdf_outline('\ue80a'),
|
||||
szf_file_percent_outline('\ue80b'),
|
||||
szf_file_powerpoint_outline('\ue80c'),
|
||||
szf_file_video_outline('\ue80d'),
|
||||
szf_file_word_outline('\ue80e'),
|
||||
szf_message_processing_outline('\ue80f'),
|
||||
szf_notebook_outline('\ue810'),
|
||||
szf_zip_box_outline('\ue811');
|
||||
|
||||
override val typeface: ITypeface by lazy { SzkolnyFont }
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
BIN
szkolny-font/src/main/res/font/szkolny_font_font_v1_1.ttf
Normal file
BIN
szkolny-font/src/main/res/font/szkolny_font_font_v1_1.ttf
Normal file
Binary file not shown.
Reference in New Issue
Block a user