Compare commits

...

6 Commits

35 changed files with 1284 additions and 1095 deletions

1
.idea/.name generated Normal file
View File

@ -0,0 +1 @@
Szkolny.eu

1
.idea/misc.xml generated
View File

@ -11,6 +11,7 @@
<item index="1" class="java.lang.String" itemvalue="org.greenrobot.eventbus.Subscribe" /> <item index="1" class="java.lang.String" itemvalue="org.greenrobot.eventbus.Subscribe" />
</list> </list>
</component> </component>
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="NullableNotNullManager"> <component name="NullableNotNullManager">
<option name="myDefaultNullable" value="org.jetbrains.annotations.Nullable" /> <option name="myDefaultNullable" value="org.jetbrains.annotations.Nullable" />
<option name="myDefaultNotNull" value="androidx.annotation.RecentlyNonNull" /> <option name="myDefaultNotNull" value="androidx.annotation.RecentlyNonNull" />

View File

@ -9,7 +9,7 @@
/*secret password - removed for source code publication*/ /*secret password - removed for source code publication*/
static toys AES_IV[16] = { static toys AES_IV[16] = {
0x43, 0xb9, 0xaa, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 0x97, 0x0e, 0x93, 0xd3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat); unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);

View File

@ -67,6 +67,7 @@ import pl.szczodrzynski.edziennik.ui.modules.notifications.NotificationsFragment
import pl.szczodrzynski.edziennik.ui.modules.settings.ProfileManagerFragment import pl.szczodrzynski.edziennik.ui.modules.settings.ProfileManagerFragment
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsNewFragment import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsNewFragment
import pl.szczodrzynski.edziennik.ui.modules.timetable.v2.TimetableFragment import pl.szczodrzynski.edziennik.ui.modules.timetable.v2.TimetableFragment
import pl.szczodrzynski.edziennik.ui.modules.webpush.WebPushFragment
import pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoTouch import pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoTouch
import pl.szczodrzynski.edziennik.utils.Themes import pl.szczodrzynski.edziennik.utils.Themes
import pl.szczodrzynski.edziennik.utils.Utils import pl.szczodrzynski.edziennik.utils.Utils
@ -118,6 +119,7 @@ class MainActivity : AppCompatActivity() {
const val TARGET_HELP = 502 const val TARGET_HELP = 502
const val TARGET_FEEDBACK = 120 const val TARGET_FEEDBACK = 120
const val TARGET_MESSAGES_DETAILS = 503 const val TARGET_MESSAGES_DETAILS = 503
const val TARGET_WEB_PUSH = 140
const val HOME_ID = DRAWER_ITEM_HOME const val HOME_ID = DRAWER_ITEM_HOME
@ -209,6 +211,7 @@ class MainActivity : AppCompatActivity() {
list += NavTarget(TARGET_HELP, R.string.menu_help, HelpFragment::class) list += NavTarget(TARGET_HELP, R.string.menu_help, HelpFragment::class)
list += NavTarget(TARGET_FEEDBACK, R.string.menu_feedback, FeedbackFragment::class) list += NavTarget(TARGET_FEEDBACK, R.string.menu_feedback, FeedbackFragment::class)
list += NavTarget(TARGET_MESSAGES_DETAILS, R.string.menu_message, MessageFragment::class) list += NavTarget(TARGET_MESSAGES_DETAILS, R.string.menu_message, MessageFragment::class)
list += NavTarget(TARGET_WEB_PUSH, R.string.menu_web_push, WebPushFragment::class)
list += NavTarget(DRAWER_ITEM_DEBUG, R.string.menu_debug, DebugFragment::class) list += NavTarget(DRAWER_ITEM_DEBUG, R.string.menu_debug, DebugFragment::class)
list list
@ -229,7 +232,7 @@ class MainActivity : AppCompatActivity() {
private val fragmentManager by lazy { supportFragmentManager } private val fragmentManager by lazy { supportFragmentManager }
private lateinit var navTarget: NavTarget private lateinit var navTarget: NavTarget
private val navTargetId val navTargetId
get() = navTarget.id get() = navTarget.id
private val navBackStack = mutableListOf<NavTarget>() private val navBackStack = mutableListOf<NavTarget>()

View File

@ -14,6 +14,8 @@ import pl.szczodrzynski.edziennik.data.api.szkolny.adapter.TimeAdapter
import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.SignatureInterceptor import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.SignatureInterceptor
import pl.szczodrzynski.edziennik.data.api.szkolny.request.EventShareRequest import pl.szczodrzynski.edziennik.data.api.szkolny.request.EventShareRequest
import pl.szczodrzynski.edziennik.data.api.szkolny.request.ServerSyncRequest import pl.szczodrzynski.edziennik.data.api.szkolny.request.ServerSyncRequest
import pl.szczodrzynski.edziennik.data.api.szkolny.request.WebPushRequest
import pl.szczodrzynski.edziennik.data.api.szkolny.response.WebPushResponse
import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull
import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileFull import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileFull
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
@ -121,4 +123,34 @@ class SzkolnyApi(val app: App) {
eventId = event.id eventId = event.id
)).execute() )).execute()
} }
fun pairBrowser(browserId: String?, pairToken: String?): List<WebPushResponse.Browser> {
val response = api.webPush(WebPushRequest(
action = "pairBrowser",
deviceId = app.deviceId,
browserId = browserId,
pairToken = pairToken
)).execute().body()
return response?.data?.browsers ?: emptyList()
}
fun listBrowsers(): List<WebPushResponse.Browser> {
val response = api.webPush(WebPushRequest(
action = "listBrowsers",
deviceId = app.deviceId
)).execute().body()
return response?.data?.browsers ?: emptyList()
}
fun unpairBrowser(browserId: String): List<WebPushResponse.Browser> {
val response = api.webPush(WebPushRequest(
action = "unpairBrowser",
deviceId = app.deviceId,
browserId = browserId
)).execute().body()
return response?.data?.browsers ?: emptyList()
}
} }

View File

@ -6,8 +6,10 @@ package pl.szczodrzynski.edziennik.data.api.szkolny
import pl.szczodrzynski.edziennik.data.api.szkolny.request.EventShareRequest import pl.szczodrzynski.edziennik.data.api.szkolny.request.EventShareRequest
import pl.szczodrzynski.edziennik.data.api.szkolny.request.ServerSyncRequest import pl.szczodrzynski.edziennik.data.api.szkolny.request.ServerSyncRequest
import pl.szczodrzynski.edziennik.data.api.szkolny.request.WebPushRequest
import pl.szczodrzynski.edziennik.data.api.szkolny.response.ApiResponse import pl.szczodrzynski.edziennik.data.api.szkolny.response.ApiResponse
import pl.szczodrzynski.edziennik.data.api.szkolny.response.ServerSyncResponse import pl.szczodrzynski.edziennik.data.api.szkolny.response.ServerSyncResponse
import pl.szczodrzynski.edziennik.data.api.szkolny.response.WebPushResponse
import retrofit2.Call import retrofit2.Call
import retrofit2.http.Body import retrofit2.http.Body
import retrofit2.http.POST import retrofit2.http.POST
@ -19,4 +21,7 @@ interface SzkolnyService {
@POST("share") @POST("share")
fun shareEvent(@Body request: EventShareRequest): Call<ApiResponse<Nothing>> fun shareEvent(@Body request: EventShareRequest): Call<ApiResponse<Nothing>>
@POST("webPush")
fun webPush(@Body request: WebPushRequest): Call<ApiResponse<WebPushResponse>>
} }

View File

@ -46,6 +46,6 @@ object Signing {
/*fun provideKey(param1: String, param2: Long): ByteArray {*/ /*fun provideKey(param1: String, param2: Long): ByteArray {*/
fun pleaseStopRightNow(param1: String, param2: Long): ByteArray { fun pleaseStopRightNow(param1: String, param2: Long): ByteArray {
return "$param1.MTIzNDU2Nzg5MDz9LXSttO===.$param2".sha256() return "$param1.MTIzNDU2Nzg5MDnJqFBfu7===.$param2".sha256()
} }
} }

View File

@ -0,0 +1,14 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-12-19.
*/
package pl.szczodrzynski.edziennik.data.api.szkolny.request
data class WebPushRequest(
val action: String,
val deviceId: String,
val browserId: String? = null,
val pairToken: String? = null
)

View File

@ -0,0 +1,14 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-12-19.
*/
package pl.szczodrzynski.edziennik.data.api.szkolny.response
data class WebPushResponse(val browsers: List<Browser>) {
data class Browser(
val id: Int,
val browserId: String,
val userAgent: String,
val dateRegistered: String
)
}

View File

@ -68,6 +68,7 @@ public abstract class EventDao {
"LEFT JOIN eventTypes USING(profileId, eventType)\n" + "LEFT JOIN eventTypes USING(profileId, eventType)\n" +
"LEFT JOIN metadata ON eventId = thingId AND (thingType = " + TYPE_EVENT + " OR thingType = " + TYPE_HOMEWORK + ") AND metadata.profileId = "+profileId+"\n" + "LEFT JOIN metadata ON eventId = thingId AND (thingType = " + TYPE_EVENT + " OR thingType = " + TYPE_HOMEWORK + ") AND metadata.profileId = "+profileId+"\n" +
"WHERE events.profileId = "+profileId+" AND events.eventBlacklisted = 0 AND "+filter+"\n" + "WHERE events.profileId = "+profileId+" AND events.eventBlacklisted = 0 AND "+filter+"\n" +
"GROUP BY eventId\n" +
"ORDER BY eventDate, eventStartTime ASC"; "ORDER BY eventDate, eventStartTime ASC";
Log.d("DB", query); Log.d("DB", query);
return getAll(new SimpleSQLiteQuery(query)); return getAll(new SimpleSQLiteQuery(query));
@ -111,6 +112,7 @@ public abstract class EventDao {
"LEFT JOIN eventTypes USING(profileId, eventType)\n" + "LEFT JOIN eventTypes USING(profileId, eventType)\n" +
"LEFT JOIN metadata ON eventId = thingId AND (thingType = " + TYPE_EVENT + " OR thingType = " + TYPE_HOMEWORK + ") AND metadata.profileId = "+profileId+"\n" + "LEFT JOIN metadata ON eventId = thingId AND (thingType = " + TYPE_EVENT + " OR thingType = " + TYPE_HOMEWORK + ") AND metadata.profileId = "+profileId+"\n" +
"WHERE events.profileId = "+profileId+" AND events.eventBlacklisted = 0 AND "+filter+"\n" + "WHERE events.profileId = "+profileId+" AND events.eventBlacklisted = 0 AND "+filter+"\n" +
"GROUP BY eventId\n" +
"ORDER BY eventStartTime, addedDate ASC")); "ORDER BY eventStartTime, addedDate ASC"));
} }
public List<EventFull> getNotNotifiedNow(int profileId) { public List<EventFull> getNotNotifiedNow(int profileId) {

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-12-19.
*/
package pl.szczodrzynski.edziennik.ui
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.databinding.TemplateListItemBinding
import pl.szczodrzynski.edziennik.onClick
class TemplateAdapter(
val context: Context,
val onItemClick: ((item: TemplateItem) -> Unit)? = null,
val onItemButtonClick: ((item: TemplateItem) -> Unit)? = null
) : RecyclerView.Adapter<TemplateAdapter.ViewHolder>() {
private val app by lazy { context.applicationContext as App }
var items = listOf<TemplateItem>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val view = TemplateListItemBinding.inflate(inflater, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = items[position]
val b = holder.b
onItemClick?.let { listener ->
b.root.onClick { listener(item) }
}
/*b.someButton.visibility = if (buttonVisible) View.VISIBLE else View.GONE
onItemButtonClick?.let { listener ->
b.someButton.onClick { listener(item) }
}*/
}
override fun getItemCount() = items.size
class ViewHolder(val b: TemplateListItemBinding) : RecyclerView.ViewHolder(b.root)
data class TemplateItem(val text: String)
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-12-19.
*/
package pl.szczodrzynski.edziennik.ui.dialogs
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import me.dm7.barcodescanner.zxing.ZXingScannerView
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.dp
import kotlin.coroutines.CoroutineContext
class QrScannerDialog(
val activity: AppCompatActivity,
val onCodeScanned: (text: String) -> Unit,
val onShowListener: ((tag: String) -> Unit)? = null,
val onDismissListener: ((tag: String) -> Unit)? = null
) : CoroutineScope {
companion object {
private const val TAG = "QrScannerDialog"
}
private lateinit var app: App
private lateinit var scannerView: ZXingScannerView
private lateinit var dialog: AlertDialog
private val job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
init { run {
if (activity.isFinishing)
return@run
onShowListener?.invoke(TAG)
app = activity.applicationContext as App
scannerView = ZXingScannerView(activity)
scannerView.setPadding(0, 16.dp, 0, 0)
dialog = MaterialAlertDialogBuilder(activity)
.setTitle(R.string.qr_scanner_dialog_title)
.setView(scannerView)
.setPositiveButton(R.string.close) { dialog, _ ->
dialog.dismiss()
}
.setOnDismissListener {
onDismissListener?.invoke(TAG)
}
.show()
scannerView.setResultHandler {
scannerView.stopCamera()
dialog.dismiss()
onCodeScanned(it.text)
}
scannerView.startCamera()
}}
}

View File

@ -19,6 +19,7 @@ import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.databinding.DialogDayBinding import pl.szczodrzynski.edziennik.databinding.DialogDayBinding
import pl.szczodrzynski.edziennik.onClick import pl.szczodrzynski.edziennik.onClick
import pl.szczodrzynski.edziennik.setText import pl.szczodrzynski.edziennik.setText
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventDetailsDialog
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventListAdapter import pl.szczodrzynski.edziennik.ui.dialogs.event.EventListAdapter
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
@ -88,11 +89,17 @@ class DayDialog(
activity, activity,
onItemClick = { onItemClick = {
Toast.makeText(activity, "Event clicked ${it.topic}", Toast.LENGTH_SHORT).show() Toast.makeText(activity, "Event clicked ${it.topic}", Toast.LENGTH_SHORT).show()
EventDetailsDialog(
activity,
it,
onShowListener = onShowListener,
onDismissListener = onDismissListener
)
}, },
onEventEditClick = { onEventEditClick = {
EventManualDialog( EventManualDialog(
activity, activity,
profileId, it.profileId,
editingEvent = it, editingEvent = it,
onShowListener = onShowListener, onShowListener = onShowListener,
onDismissListener = onDismissListener onDismissListener = onDismissListener
@ -105,6 +112,7 @@ class DayDialog(
if (b.eventsView.adapter == null) { if (b.eventsView.adapter == null) {
b.eventsView.adapter = adapter b.eventsView.adapter = adapter
b.eventsView.apply { b.eventsView.apply {
isNestedScrollingEnabled = false
setHasFixedSize(true) setHasFixedSize(true)
layoutManager = LinearLayoutManager(context) layoutManager = LinearLayoutManager(context)
addItemDecoration(SimpleDividerItemDecoration(context)) addItemDecoration(SimpleDividerItemDecoration(context))

View File

@ -1,47 +0,0 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-11-12.
*/
package pl.szczodrzynski.edziennik.ui.dialogs.event
import android.app.Activity
import androidx.appcompat.app.AlertDialog
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.Time
class EventAddTypeDialog(
val activity: Activity,
val profileId: Int,
val date: Date? = null,
val time: Time? = null
) {
companion object {
private const val TAG = "EventAddTypeDialog"
}
private lateinit var dialog: AlertDialog
init { run {
dialog = MaterialAlertDialogBuilder(activity)
.setItems(R.array.main_menu_add_options) { dialog, which ->
dialog.dismiss()
EventManualDialogOld(activity, profileId)
.show(
activity.application as App,
null,
date,
time,
when (which) {
1 -> EventManualDialogOld.DIALOG_HOMEWORK
else -> EventManualDialogOld.DIALOG_EVENT
}
)
}
.setNegativeButton(R.string.cancel) { dialog, _ -> dialog.dismiss() }
.show()
}}
}

View File

@ -0,0 +1,158 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-12-18.
*/
package pl.szczodrzynski.edziennik.ui.dialogs.event
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.*
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.task.SzkolnyTask
import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull
import pl.szczodrzynski.edziennik.databinding.DialogEventDetailsBinding
import pl.szczodrzynski.edziennik.utils.models.Date
import kotlin.coroutines.CoroutineContext
class EventDetailsDialog(
val activity: AppCompatActivity,
val event: EventFull,
val onShowListener: ((tag: String) -> Unit)? = null,
val onDismissListener: ((tag: String) -> Unit)? = null
) : CoroutineScope {
companion object {
private const val TAG = "EventDetailsDialog"
}
private lateinit var app: App
private lateinit var b: DialogEventDetailsBinding
private lateinit var dialog: AlertDialog
private var removeEventDialog: AlertDialog? = null
private val eventShared = event.sharedBy != null
private val eventOwn = event.sharedBy == "self"
private val job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
private lateinit var adapter: EventListAdapter
init { run {
if (activity.isFinishing)
return@run
onShowListener?.invoke(TAG)
app = activity.applicationContext as App
b = DialogEventDetailsBinding.inflate(activity.layoutInflater)
dialog = MaterialAlertDialogBuilder(activity)
.setView(b.root)
.setPositiveButton(R.string.close) { dialog, _ ->
dialog.dismiss()
}
.apply {
if (event.addedManually)
setNeutralButton(R.string.remove, null)
}
.setOnDismissListener {
onDismissListener?.invoke(TAG)
}
.show()
dialog.getButton(AlertDialog.BUTTON_NEUTRAL)?.onClick {
showRemoveEventDialog()
}
update()
}}
private fun update() {
b.event = event
b.eventShared = eventShared
b.eventOwn = eventOwn
val bullet = ""
val colorSecondary = android.R.attr.textColorSecondary.resolveAttr(activity)
try {
b.monthName = app.resources.getStringArray(R.array.months_day_of_array)[event.eventDate.month - 1]
}
catch (_: Exception) {}
b.typeColor.background?.setTintColor(event.getColor())
b.details = mutableListOf(
event.subjectLongName,
event.teamName?.asColoredSpannable(colorSecondary)
).concat(bullet)
b.addedBy.setText(
when (event.sharedBy) {
null -> when {
event.addedManually -> R.string.event_details_added_by_self_format
event.teacherFullName == null -> R.string.event_details_added_by_unknown_format
else -> R.string.event_details_added_by_format
}
"self" -> R.string.event_details_shared_by_self_format
else -> R.string.event_details_shared_by_format
},
Date.fromMillis(event.addedDate).formattedString,
event.sharedByName ?: event.teacherFullName ?: ""
)
}
private fun showRemoveEventDialog() {
val shareNotice = when {
eventShared && eventOwn -> "\n\n"+activity.getString(R.string.dialog_event_manual_remove_shared_self)
eventShared && !eventOwn -> "\n\n"+activity.getString(R.string.dialog_event_manual_remove_shared)
else -> ""
}
removeEventDialog = MaterialAlertDialogBuilder(activity)
.setTitle(R.string.are_you_sure)
.setMessage(activity.getString(R.string.dialog_register_event_manual_remove_confirmation)+shareNotice)
.setPositiveButton(R.string.yes, null)
.setNegativeButton(R.string.no) { dialog, _ -> dialog.dismiss() }
.create()
.apply {
setOnShowListener { dialog ->
val positiveButton = (dialog as AlertDialog).getButton(AlertDialog.BUTTON_POSITIVE)
positiveButton?.setOnClickListener {
removeEvent()
}
}
show()
}
}
private fun removeEvent() {
if (eventShared && eventOwn) {
Toast.makeText(activity, "Unshare + remove own event", Toast.LENGTH_SHORT).show()
SzkolnyTask.unshareEvent(event).enqueue(activity)
finishRemoving()
}
else if (eventShared && !eventOwn) {
Toast.makeText(activity, "Remove + blacklist somebody's event", Toast.LENGTH_SHORT).show()
// TODO
}
else {
Toast.makeText(activity, "Remove event", Toast.LENGTH_SHORT).show()
finishRemoving()
}
}
private fun finishRemoving() {
launch {
withContext(Dispatchers.Default) {
app.db.eventDao().remove(event)
}
}
removeEventDialog?.dismiss()
dialog.dismiss()
Toast.makeText(activity, R.string.removed, Toast.LENGTH_SHORT).show()
if (activity is MainActivity && activity.navTargetId == MainActivity.DRAWER_ITEM_AGENDA)
activity.reloadTarget()
}
}

View File

@ -19,6 +19,7 @@ import com.jaredrummler.android.colorpicker.ColorPickerDialog
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener import com.jaredrummler.android.colorpicker.ColorPickerDialogListener
import kotlinx.coroutines.* import kotlinx.coroutines.*
import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA
import pl.szczodrzynski.edziennik.data.api.task.SzkolnyTask import pl.szczodrzynski.edziennik.data.api.task.SzkolnyTask
import pl.szczodrzynski.edziennik.data.db.modules.events.Event import pl.szczodrzynski.edziennik.data.db.modules.events.Event
import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull
@ -86,6 +87,7 @@ class EventManualDialog(
.setOnDismissListener { .setOnDismissListener {
onDismissListener?.invoke(TAG) onDismissListener?.invoke(TAG)
} }
.setCancelable(false)
.create() .create()
.apply { .apply {
setOnShowListener { dialog -> setOnShowListener { dialog ->
@ -461,7 +463,7 @@ class EventManualDialog(
b.teacherDropdown.deselect() b.teacherDropdown.deselect()
} }
else { else {
defaultTime?.let { val setTime: (Time) -> Unit = {
event.startTime = it event.startTime = it
if (b.timeDropdown.select(it) == null) if (b.timeDropdown.select(it) == null)
b.timeDropdown.select(TextInputDropDown.Item( b.timeDropdown.select(TextInputDropDown.Item(
@ -470,23 +472,10 @@ class EventManualDialog(
tag = it tag = it
)) ))
} }
defaultTime?.let(setTime)
editingEvent?.startTime?.let { editingEvent?.startTime?.let(setTime)
if (b.timeDropdown.select(it) == null) defaultLesson?.displayStartTime?.let(setTime)
b.timeDropdown.select(TextInputDropDown.Item( defaultHour?.let(setTime)
it.value.toLong(),
it.stringHM,
tag = it
))
}
defaultLesson?.let {
b.timeDropdown.select(it.displayStartTime?.value?.toLong())
}
defaultHour?.let {
b.timeDropdown.select(it.value.toLong())
}
} }
defaultLoaded = true defaultLoaded = true
b.timeDropdown.isEnabled = true b.timeDropdown.isEnabled = true
@ -554,7 +543,7 @@ class EventManualDialog(
private fun saveEvent() { private fun saveEvent() {
val date = b.dateDropdown.selected?.tag.instanceOfOrNull<Date>() val date = b.dateDropdown.selected?.tag.instanceOfOrNull<Date>()
val lesson = b.timeDropdown.selected?.tag.instanceOfOrNull<LessonFull>() val startTime = b.timeDropdown.selected?.tag.instanceOfOrNull<Time>()
val teamId = b.teamDropdown.selected?.id val teamId = b.teamDropdown.selected?.id
val type = b.typeDropdown.selected?.id val type = b.typeDropdown.selected?.id
val topic = b.topic.text?.toString() val topic = b.topic.text?.toString()
@ -592,7 +581,7 @@ class EventManualDialog(
profileId, profileId,
editingEvent?.id ?: id, editingEvent?.id ?: id,
date, date,
lesson?.displayStartTime, startTime,
topic, topic,
customColor ?: -1, customColor ?: -1,
type?.toInt() ?: Event.TYPE_DEFAULT, type?.toInt() ?: Event.TYPE_DEFAULT,
@ -679,7 +668,7 @@ class EventManualDialog(
dialog.dismiss() dialog.dismiss()
Toast.makeText(activity, R.string.saved, Toast.LENGTH_SHORT).show() Toast.makeText(activity, R.string.saved, Toast.LENGTH_SHORT).show()
if (activity is MainActivity) if (activity is MainActivity && activity.navTargetId == DRAWER_ITEM_AGENDA)
activity.reloadTarget() activity.reloadTarget()
} }
private fun finishRemoving() { private fun finishRemoving() {
@ -692,7 +681,7 @@ class EventManualDialog(
removeEventDialog?.dismiss() removeEventDialog?.dismiss()
dialog.dismiss() dialog.dismiss()
Toast.makeText(activity, R.string.removed, Toast.LENGTH_SHORT).show() Toast.makeText(activity, R.string.removed, Toast.LENGTH_SHORT).show()
if (activity is MainActivity) if (activity is MainActivity && activity.navTargetId == DRAWER_ITEM_AGENDA)
activity.reloadTarget() activity.reloadTarget()
} }
} }

View File

@ -1,885 +0,0 @@
package pl.szczodrzynski.edziennik.ui.dialogs.event;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.ColorInt;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.PopupMenu;
import androidx.appcompat.widget.SwitchCompat;
import androidx.lifecycle.Observer;
import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.google.android.material.textfield.TextInputEditText;
import com.google.android.material.textfield.TextInputLayout;
import com.google.gson.JsonObject;
import com.jaredrummler.android.colorpicker.ColorPickerDialog;
import com.jaredrummler.android.colorpicker.ColorPickerDialogListener;
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.wdullaer.materialdatetimepicker.date.DatePickerDialog;
import com.wdullaer.materialdatetimepicker.time.TimePickerDialog;
import java.util.List;
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.events.EventFull;
import pl.szczodrzynski.edziennik.data.db.modules.events.EventType;
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull;
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata;
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile;
import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileFull;
import pl.szczodrzynski.edziennik.data.db.modules.subjects.Subject;
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher;
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team;
import pl.szczodrzynski.edziennik.network.ServerRequest;
import pl.szczodrzynski.edziennik.utils.TextInputDropDown;
import pl.szczodrzynski.edziennik.utils.Themes;
import pl.szczodrzynski.edziennik.utils.models.Date;
import pl.szczodrzynski.edziennik.utils.models.Time;
import pl.szczodrzynski.edziennik.utils.models.Week;
import static pl.szczodrzynski.edziennik.App.APP_URL;
import static pl.szczodrzynski.edziennik.data.db.modules.events.Event.COLOR_DEFAULT;
import static pl.szczodrzynski.edziennik.data.db.modules.events.Event.TYPE_HOMEWORK;
import static pl.szczodrzynski.edziennik.data.db.modules.events.Event.TYPE_UNDEFINED;
import static pl.szczodrzynski.edziennik.utils.Utils.bs;
import static pl.szczodrzynski.edziennik.utils.Utils.ns;
public class EventManualDialogOld {
private static final String TAG = "EventManualDialogOld";
private App app;
private Context context;
private int profileId;
private ProfileFull profile = null;
public EventManualDialogOld(Context context, int profileId) {
this.context = context;
this.activity = (AppCompatActivity) context;
this.profileId = profileId;
}
public EventManualDialogOld(Context context) {
this.context = context;
this.activity = (AppCompatActivity) context;
this.profileId = App.profileId;
}
private AppCompatActivity activity;
private MaterialDialog dialog;
private View dialogView;
private TextInputLayout registerEventManualDateLayout;
private TextInputDropDown registerEventManualDate;
private TextInputLayout registerEventManualLessonLayout;
private TextInputDropDown registerEventManualLesson;
private TextInputLayout registerEventManualTeamLayout;
private TextInputDropDown registerEventManualTeam;
private SwitchCompat registerEventManualShare;
private TextView registerEventManualShareText;
private TextInputLayout registerEventManualTypeLayout;
private TextInputDropDown registerEventManualType;
private TextInputLayout registerEventManualTopicLayout;
private TextInputEditText registerEventManualTopic;
private TextInputDropDown registerEventManualTeacher;
private TextInputDropDown registerEventManualSubject;
private View registerEventManualColorPreview;
private Button registerEventManualColorChoose;
private Date lessonDate = Date.getToday();
private Time lessonStartTime = null;
private long lessonTeamId = -1;
private long lessonTeacherId = -1;
private long lessonSubjectId = -1;
private boolean lessonSelected = false;
private int eventType = TYPE_UNDEFINED;
private int eventColor = -1;
private EventFull editingEvent = null;
private MaterialDialog progressDialog;
private void updateButtonCaption()
{
String buttonCaption = "";
buttonCaption += Week.getFullDayName(Week.getWeekDayFromDate(lessonDate));
buttonCaption += ", ";
buttonCaption += lessonDate.getFormattedString();
registerEventManualDate.setText(buttonCaption);
registerEventManualLesson.setText(R.string.dialog_event_manual_choose_lesson);
lessonStartTime = null;
//lessonSubjectId = -1;
//lessonTeacherId = -1;
}
private void updateSubjectTeacher() {
AsyncTask.execute(() -> {
Subject subject = app.db.subjectDao().getByIdNow(profileId, lessonSubjectId);
Teacher teacher = app.db.teacherDao().getByIdNow(profileId, lessonTeacherId);
activity.runOnUiThread(() -> {
if (lessonTeacherId == -1 || teacher == null)
registerEventManualTeacher.setText(R.string.dialog_event_manual_no_teacher);
else
registerEventManualTeacher.setText(teacher.getFullName());
if (lessonSubjectId == -1 || subject == null)
registerEventManualSubject.setText(R.string.dialog_event_manual_no_subject);
else
registerEventManualSubject.setText(subject.longName);
});
});
}
private void addEvent()
{
registerEventManualDateLayout.setError(null);
registerEventManualLessonLayout.setError(null);
registerEventManualTeamLayout.setError(null);
registerEventManualTopicLayout.setError(null);
registerEventManualTypeLayout.setError(null);
boolean errors = false;
if (!lessonSelected) {
registerEventManualLessonLayout.setError(app.getString(R.string.dialog_event_manual_lesson_choose));
errors = true;
}
if (registerEventManualShare.isChecked() && lessonTeamId == -1) {
registerEventManualTeamLayout.setError(app.getString(R.string.dialog_event_manual_team_choose));
errors = true;
}
if (eventType == -2) {
registerEventManualTypeLayout.setError(app.getString(R.string.dialog_event_manual_type_choose));
errors = true;
}
if (registerEventManualTopic.getText() == null || registerEventManualTopic.getText().toString().isEmpty()) {
registerEventManualTopicLayout.setError(app.getString(R.string.dialog_event_manual_topic_choose));
errors = true;
}
if (errors)
return;
long id = System.currentTimeMillis();
Event event = new Event(
profileId,
id,
lessonDate,
lessonStartTime,
registerEventManualTopic.getText().toString(),
eventColor,
eventType,
true,
lessonTeacherId,
lessonSubjectId,
lessonTeamId
);
Metadata metadata = new Metadata(
profileId,
eventType == TYPE_HOMEWORK ? Metadata.TYPE_HOMEWORK : Metadata.TYPE_EVENT,
event.id,
true,
true,
System.currentTimeMillis()
);
if (editingEvent != null) {
event.id = editingEvent.id;
metadata.thingId = event.id;
metadata.addedDate = editingEvent.addedDate;
}
if (registerEventManualShare.isChecked()) {
if (profile.getRegistration() != Profile.REGISTRATION_ENABLED) {
new MaterialDialog.Builder(context)
.title(R.string.dialog_event_manual_must_register_title)
.content(R.string.dialog_event_manual_must_register_text)
.positiveText(R.string.i_agree)
.negativeText(R.string.no_thanks)
.neutralText(R.string.more)
.onPositive(((dialog1, which) -> {
profile.setRegistration(Profile.REGISTRATION_ENABLED);
app.profileSaveAsync(profile);
}))
.onNeutral(((dialog1, which) -> {
new MaterialDialog.Builder(context)
.title(R.string.help)
.content(app.getString(R.string.help_register_agreement))
.positiveText(R.string.ok)
.show();
}))
.show();
return;
}
if (!profile.getEnableSharedEvents()) {
new MaterialDialog.Builder(context)
.title(R.string.dialog_event_manual_shared_disabled_title)
.content(R.string.dialog_event_manual_shared_disabled_text)
.positiveText(R.string.sure)
.negativeText(R.string.no_thanks)
.onPositive(((dialog1, which) -> {
profile.setEnableSharedEvents(true);
app.profileSaveAsync(profile);
}))
.show();
return;
}
if (editingEvent != null
&& editingEvent.sharedBy != null
&& !editingEvent.sharedBy.equals("self")) {
// editing a shared event, and event was shared by someone else
// send a edit request
shareEvent(event, metadata, MODE_REQUEST);
}
else {
// editing a self-shared event, not-shared event or a new event, but want to share it
// post a new event to database
shareEvent(event, metadata, MODE_SHARE);
}
}
else if (editingEvent != null
&& editingEvent.sharedBy != null
&& editingEvent.sharedBy.equals("self")) {
// the event was self-shared, but needs to be removed now (from the server)
shareEvent(event, metadata, MODE_UNSHARE);
}
else {
// editing a local event
finishAdding(event, metadata);
}
}
private static final int MODE_SHARE = 0;
private static final int MODE_UNSHARE = 1;
private static final int MODE_REQUEST = 2;
private static final int MODE_UNSHARE_REMOVE = 3;
private void shareEvent(Event event, Metadata metadata, int mode) {
AsyncTask.execute(() -> {
ServerRequest syncRequest =
new ServerRequest(
app,
app.requestScheme + APP_URL + "main.php?share",
"RegisterEventManualDialog/SH",
profile);
String teamUnshare = "";
if (mode == MODE_SHARE) {
if (editingEvent != null
&& event.teamId != editingEvent.teamId) {
// team ID was changed. Need to remove the event for other teams
teamUnshare = app.db.teamDao().getCodeByIdNow(profile.getId(), editingEvent.teamId);
syncRequest.setBodyParameter("team_unshare", teamUnshare);
}
syncRequest.setBodyParameter("event", app.gson.toJson(event));
syncRequest.setBodyParameter("event_addedDate", Long.toString(metadata.addedDate));
syncRequest.setBodyParameter("team", app.db.teamDao().getCodeByIdNow(profile.getId(), event.teamId));
}
else if (mode == MODE_UNSHARE
&& editingEvent != null) {
teamUnshare = app.db.teamDao().getCodeByIdNow(profile.getId(), editingEvent.teamId);
syncRequest.setBodyParameter("remove_id", Long.toString(editingEvent.id));
syncRequest.setBodyParameter("team_unshare", teamUnshare);
}
else if (mode == MODE_UNSHARE_REMOVE
&& editingEvent != null) {
teamUnshare = app.db.teamDao().getCodeByIdNow(profile.getId(), editingEvent.teamId);
syncRequest.setBodyParameter("remove_id", Long.toString(editingEvent.id));
syncRequest.setBodyParameter("team_unshare", teamUnshare);
}
else if (mode == MODE_REQUEST) {
activity.runOnUiThread(() -> {
new MaterialDialog.Builder(context)
.title(R.string.error_occured)
.content(R.string.error_shared_edit_requests_not_implemented)
.positiveText(R.string.ok)
.show();
});
return;
}
activity.runOnUiThread(() -> {
progressDialog = new MaterialDialog.Builder(context)
.title(R.string.loading)
.content(R.string.sharing_event)
.progress(true, 0)
.canceledOnTouchOutside(false)
.show();
});
String finalTeamUnshare = teamUnshare;
try {
JsonObject result = syncRequest.runSync();
activity.runOnUiThread(() -> progressDialog.dismiss());
if (result == null) {
activity.runOnUiThread(() -> new MaterialDialog.Builder(context)
.title(R.string.error_occured)
.content(R.string.sync_error_no_internet)
.positiveText(R.string.ok)
.show());
return;
}
if (result.get("success") == null || !result.get("success").getAsString().equals("true")) {
activity.runOnUiThread(() -> new MaterialDialog.Builder(context)
.title(R.string.error_occured)
.content(R.string.sync_error_app_server)
.positiveText(R.string.ok)
.show());
return;
}
if (mode == MODE_SHARE) {
event.sharedBy = "self";
event.sharedByName = profile.getStudentNameLong();
}
else if (mode == MODE_UNSHARE) {
event.sharedBy = null;
}
// check all profiles
// remove if necessary (team matching)
// this will hardly ever need to run
// (only if the user un-shares an event and has two profiles sharing the same team in common)
if (finalTeamUnshare != null && !finalTeamUnshare.equals("")) {
app.db.eventDao().removeByTeamId(editingEvent.teamId, editingEvent.id);
}
if (mode == MODE_UNSHARE_REMOVE
&& editingEvent != null) {
editingEvent.sharedBy = null;
AsyncTask.execute(() -> {
app.db.eventDao().remove(editingEvent);
});
activity.runOnUiThread(() -> {
Toast.makeText(app, R.string.removed, Toast.LENGTH_SHORT).show();
if (activity instanceof MainActivity)
((MainActivity) activity).reloadTarget();
dialog.dismiss();
});
}
else {
activity.runOnUiThread(() -> {
finishAdding(event, metadata);
});
}
} catch (Exception e) {
activity.runOnUiThread(() -> {
// TODO show error in EventManualDialogOld
//app.apiEdziennik.guiShowErrorDialog(activity, new AppError(TAG, 379, CODE_OTHER, null, e), R.string.error_occured);
});
}
});
}
private void finishAdding(Event event, Metadata metadata) {
AsyncTask.execute(() -> {
app.db.eventDao().add(event);
app.db.metadataDao().add(metadata);
if (editingEvent != null && (event.type == TYPE_HOMEWORK) != (editingEvent.type == TYPE_HOMEWORK)) {
// editingEvent's type changed
// the old metadata will not work because either the event changed *to* or *from* homework.
app.db.metadataDao().delete(
profileId,
editingEvent.type == TYPE_HOMEWORK ? Metadata.TYPE_HOMEWORK : Metadata.TYPE_EVENT,
editingEvent.id
);
}
});
Toast.makeText(app, R.string.saved, Toast.LENGTH_SHORT).show();
dialog.dismiss();
if (activity instanceof MainActivity)
((MainActivity) activity).reloadTarget();
}
private DialogInterface.OnDismissListener dismissListener;
private boolean callDismissListener = true;
public EventManualDialogOld withDismissListener(DialogInterface.OnDismissListener dismissListener) {
this.dismissListener = dismissListener;
return this;
}
private void performDismiss(DialogInterface dialogInterface) {
if (!dialog.isCancelled())
dialog.dismiss();
if (callDismissListener && dismissListener != null) {
dismissListener.onDismiss(dialogInterface);
}
callDismissListener = true;
}
public static final int DIALOG_EVENT = 0;
public static final int DIALOG_HOMEWORK = 1;
public void show(App _app, EventFull editingEvent, Date defaultDate, Time defaultTime, int dialogType) {
if (!(context instanceof Activity))
return;
this.app = _app;
AsyncTask.execute(() -> {
this.profile = app.db.profileDao().getFullByIdNow(profileId);
if (profile != null) {
((Activity) context).runOnUiThread(() -> {
actualShow(editingEvent, defaultDate, defaultTime, dialogType);
});
}
else {
activity.runOnUiThread(() -> {
new MaterialDialog.Builder(activity)
.title(R.string.error_occured)
.content(R.string.sync_error_profile_not_found)
.positiveText(R.string.ok)
.show();
});
}
});
}
private void actualShow(EventFull editingEvent, Date defaultDate, Time defaultTime, int dialogType) {
if (dialogType == DIALOG_HOMEWORK) {
eventType = TYPE_HOMEWORK;
eventColor = -1;
}
dialog = new MaterialDialog.Builder(context)
.title((dialogType == DIALOG_EVENT ? R.string.dialog_register_event_manual_title : R.string.dialog_register_homework_manual_title))
.customView(R.layout.dialog_event_manual, true)
.positiveText(R.string.save)
.negativeText(R.string.cancel)
.autoDismiss(false)
.onPositive((dialog, which) -> addEvent())
.onNegative((dialog, which) -> dialog.dismiss())
.onNeutral((dialog, which) -> {
if (editingEvent != null) {
String sharedNotice = "";
// notify the user that the event will be removed from all users
if (editingEvent.sharedBy != null
&& editingEvent.sharedBy.equals("self")) {
sharedNotice += "\n\n"+context.getString(R.string.dialog_event_manual_remove_shared_self);
}
// notify the user that the event will be blacklisted and removed only locally
else if (editingEvent.sharedBy != null) {
sharedNotice += "\n\n"+context.getString(R.string.dialog_event_manual_remove_shared);
}
new MaterialDialog.Builder(context)
.title(R.string.are_you_sure)
.content(context.getString(R.string.dialog_register_event_manual_remove_confirmation)+sharedNotice)
.positiveText(R.string.yes)
.negativeText(R.string.no)
.onPositive((dialog1, which1) -> {
if (editingEvent.sharedBy != null
&& editingEvent.sharedBy.equals("self")) {
// editing event was self-shared
// the shared event needs to be unshared, then removed locally
shareEvent(editingEvent, null, MODE_UNSHARE_REMOVE);
return;
}
else if (editingEvent.sharedBy != null) {
// the event is shared by someone else
// blacklist it and remove only locally
AsyncTask.execute(() -> {
editingEvent.blacklisted = true;
app.db.eventDao().setBlacklisted(editingEvent.profileId, editingEvent.id, true);
});
}
else {
// the event is not shared nor blacklisted - just remove it
AsyncTask.execute(() -> {
app.db.eventDao().remove(editingEvent);
});
}
dialog.dismiss();
dialog1.dismiss();
Toast.makeText(app, R.string.removed, Toast.LENGTH_SHORT).show();
if (activity instanceof MainActivity)
((MainActivity) activity).reloadTarget();
})
.show();
}
})
.dismissListener((this::performDismiss))
.show();
if (editingEvent != null) {
//&& (editingEvent.sharedBy == null || editingEvent.sharedBy.equals("self"))) {
dialog.setActionButton(DialogAction.NEUTRAL, R.string.remove);
}
dialogView = dialog.getCustomView();
assert dialogView != null;
@ColorInt int primaryTextColor = Themes.INSTANCE.getPrimaryTextColor(context);
registerEventManualDateLayout = dialogView.findViewById(R.id.registerEventManualDateLayout);
registerEventManualDate = dialogView.findViewById(R.id.registerEventManualDate);
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);
registerEventManualTeamLayout = dialogView.findViewById(R.id.registerEventManualTeamLayout);
registerEventManualTeam = dialogView.findViewById(R.id.registerEventManualTeam);
registerEventManualTeacher = dialogView.findViewById(R.id.registerEventManualTeacher);
registerEventManualSubject = dialogView.findViewById(R.id.registerEventManualSubject);
registerEventManualTypeLayout = dialogView.findViewById(R.id.registerEventManualTypeLayout);
registerEventManualType = dialogView.findViewById(R.id.registerEventManualType);
registerEventManualTopicLayout = dialogView.findViewById(R.id.registerEventManualTopicLayout);
registerEventManualTopic = dialogView.findViewById(R.id.registerEventManualTopic);
registerEventManualShare = dialogView.findViewById(R.id.registerEventManualShare);
registerEventManualShareText = dialogView.findViewById(R.id.registerEventManualShareText);
registerEventManualShare.setOnCheckedChangeListener(((buttonView, isChecked) -> {
// show notice text if share is enabled or event is already shared
registerEventManualShareText.setVisibility(isChecked || (editingEvent != null && editingEvent.sharedBy != null) ? View.VISIBLE : View.GONE);
// notify the user if he wants to share the event with no team selected
if (isChecked && lessonTeamId == -1) {
Toast.makeText(context, R.string.dialog_event_manual_cannot_share, Toast.LENGTH_SHORT).show();
}
if (editingEvent != null && editingEvent.sharedBy != null) {
// if the event is already shared, show the (change) or (removal) notice text
if (isChecked)
registerEventManualShareText.setText(R.string.dialog_event_manual_share_will_change);
else
registerEventManualShareText.setText(R.string.dialog_event_manual_share_will_remove);
}
}));
registerEventManualDate.setOnClickListener(v -> DatePickerDialog.newInstance(
(view, year, monthOfYear, dayOfMonth) -> {
lessonDate.year = year;
lessonDate.month = monthOfYear + 1;
lessonDate.day = dayOfMonth;
updateButtonCaption();
},
lessonDate.year,
lessonDate.month - 1,
lessonDate.day
).show(((AppCompatActivity) context).getSupportFragmentManager(), "DatePickerDialog"));
registerEventManualLesson.setOnClickListener(v -> {
app.db.lessonDao().getAllByDateWithoutChanges(profileId, lessonDate).observe(activity, new Observer<List<LessonFull>>() {
@Override
public void onChanged(@Nullable List<LessonFull> lessons) {
PopupMenu popup = new PopupMenu(context, registerEventManualLesson);
if (lessons != null && lessons.size() != 0) {
for (LessonFull lesson: lessons) {
int index = lessons.indexOf(lesson);
popup.getMenu().add(
0,
index,
index+1,
lesson.startTime.getStringHM()+" "+bs(lesson.subjectLongName));
}
}
popup.getMenu().add(1, -1, 0, R.string.dialog_event_manual_all_day);
popup.getMenu().add(1, 0, 100, R.string.dialog_event_manual_custom_time);
popup.setOnMenuItemClickListener(item -> {
if (lessons != null && item.getGroupId() == 0) {
LessonFull lesson = lessons.get(item.getItemId());
lessonTeacherId = lesson.teacherId;
lessonStartTime = lesson.startTime;
lessonSubjectId = lesson.subjectId;
registerEventManualTeacher.setText(bs(lesson.teacherFullName));
registerEventManualSubject.setText(bs(lesson.subjectLongName));
lessonTeamId = lesson.teamId;
registerEventManualTeam.setText(ns(context.getString(R.string.dialog_event_manual_no_team), bs(lesson.teamName)));
registerEventManualLesson.setText(item.getTitle());
lessonSelected = true;
}
else if (item.getGroupId() == 1) {
if (item.getItemId() == -1) {
lessonStartTime = null;
lessonTeacherId = -1;
lessonSubjectId = -1;
if (editingEvent != null) {
lessonTeacherId = editingEvent.teacherId;
lessonSubjectId = editingEvent.subjectId;
}
updateSubjectTeacher();
registerEventManualLesson.setText(item.getTitle());
lessonSelected = true;
return true;
}
Time now = Time.getNow();
TimePickerDialog.newInstance((view, hourOfDay, minute, second) -> {
lessonStartTime = new Time(hourOfDay, minute, second);
lessonTeacherId = -1;
lessonSubjectId = -1;
if (editingEvent != null) {
lessonTeacherId = editingEvent.teacherId;
lessonSubjectId = editingEvent.subjectId;
}
updateSubjectTeacher();
//lessonTeamId = -1;
registerEventManualLesson.setText(lessonStartTime.getStringHM());
lessonSelected = true;
}, now.hour, now.minute, 0, true).show(((AppCompatActivity) context).getSupportFragmentManager(), "TimePickerDialog");
}
return true;
});
popup.show();
app.db.lessonDao().getAllByDateWithoutChanges(profileId, lessonDate).removeObserver(this);
}
});
});
registerEventManualTeam.setOnClickListener(v -> {
app.db.teamDao().getAll(profileId).observe(activity, new Observer<List<Team>>() {
@Override
public void onChanged(@Nullable List<Team> teams) {
PopupMenu popup = new PopupMenu(context, registerEventManualTeam);
if (teams != null && teams.size() != 0) {
int index = 0;
for (Team team : teams) {
popup.getMenu().add(0, index++, (index)+1, team.name);
}
}
popup.getMenu().add(1, 0, 100, context.getString(R.string.dialog_event_manual_no_team));
popup.setOnMenuItemClickListener(item -> {
long id = -1;
if (item.getGroupId() == 0 && teams != null) {
Team team = teams.get(item.getItemId());
id = team.id;
}
lessonTeamId = id;
registerEventManualTeam.setText(item.getTitle());
return true;
});
popup.show();
app.db.teamDao().getAll(profileId).removeObserver(this);
}
});
});
registerEventManualTeacher.setOnClickListener(v -> {
app.db.teacherDao().getAllTeachers(profileId).observe(activity, new Observer<List<Teacher>>() {
@Override
public void onChanged(@Nullable List<Teacher> teachers) {
PopupMenu popup = new PopupMenu(context, registerEventManualTeacher);
if (teachers != null && teachers.size() != 0) {
int index = 0;
for (Teacher teacher : teachers) {
popup.getMenu().add(0, index++, (index)+1, teacher.getFullName());
}
}
popup.getMenu().add(1, 0, 0, context.getString(R.string.dialog_event_manual_no_teacher));
popup.setOnMenuItemClickListener(item -> {
long id = -1;
if (item.getGroupId() == 0 && teachers != null) {
Teacher teacher = teachers.get(item.getItemId());
id = teacher.id;
}
lessonTeacherId = id;
registerEventManualTeacher.setText(item.getTitle());
return true;
});
popup.show();
app.db.teacherDao().getAllTeachers(profileId).removeObserver(this);
}
});
});
registerEventManualSubject.setOnClickListener(v -> {
app.db.subjectDao().getAll(profileId).observe(activity, new Observer<List<Subject>>() {
@Override
public void onChanged(@Nullable List<Subject> subjects) {
PopupMenu popup = new PopupMenu(context, registerEventManualSubject);
if (subjects != null && subjects.size() != 0) {
int index = 0;
for (Subject subject: subjects) {
popup.getMenu().add(0, index++, (index)+1, subject.longName);
}
}
popup.getMenu().add(1, 0, 0, context.getString(R.string.dialog_event_manual_no_subject));
popup.setOnMenuItemClickListener(item -> {
long id = -1;
if (item.getGroupId() == 0 && subjects != null) {
Subject subject = subjects.get(item.getItemId());
id = subject.id;
}
lessonSubjectId = id;
registerEventManualSubject.setText(item.getTitle());
return true;
});
popup.show();
app.db.subjectDao().getAll(profileId).removeObserver(this);
}
});
});
registerEventManualType.setOnClickListener(v -> {
app.db.eventTypeDao().getAll(profileId).observe(activity, new Observer<List<EventType>>() {
@Override
public void onChanged(@Nullable List<EventType> eventTypes) {
PopupMenu popup = new PopupMenu(context, registerEventManualType);
if (eventTypes != null && eventTypes.size() != 0) {
int index = 0;
for (EventType eventType : eventTypes) {
popup.getMenu().add(0, index++, (index)+1, eventType.name);
}
}
popup.setOnMenuItemClickListener(item -> {
if (item.getGroupId() == 0 && eventTypes != null) {
EventType typeObj = eventTypes.get(item.getItemId());
eventType = (int)typeObj.id;
eventColor = -1; // set -1 as it's the event type's default color
registerEventManualColorPreview.setBackgroundColor(typeObj.color); // set event type's color here to show how will it look
}
registerEventManualType.setText(item.getTitle());
return true;
});
popup.show();
app.db.eventTypeDao().getAll(profileId).removeObserver(this);
}
});
});
View.OnClickListener colorChooseOnClick = (v -> {
AsyncTask.execute(() -> {
EventType type = app.db.eventTypeDao().getByIdNow(profileId, eventType);
activity.runOnUiThread(() -> {
ColorPickerDialog colorPickerDialog = ColorPickerDialog.newBuilder()
.setColor(eventColor != -1 ? eventColor : type != null ? type.color : COLOR_DEFAULT)
.create();
colorPickerDialog.setColorPickerDialogListener(
new ColorPickerDialogListener() {
@Override
public void onColorSelected(int dialogId, int color) {
registerEventManualColorPreview.setBackgroundColor(color);
eventColor = color;
}
@Override
public void onDialogDismissed(int dialogId) {
}
});
colorPickerDialog.show(((Activity)context).getFragmentManager(), "color-picker-dialog");
});
});
});
registerEventManualColorPreview = dialogView.findViewById(R.id.registerEventManualColorPreview);
registerEventManualColorPreview.setOnClickListener(colorChooseOnClick);
registerEventManualColorChoose = dialogView.findViewById(R.id.registerEventManualColorChoose);
registerEventManualColorChoose.setOnClickListener(colorChooseOnClick);
if (eventType != TYPE_UNDEFINED) {
AsyncTask.execute(() -> {
EventType type = app.db.eventTypeDao().getByIdNow(profileId, eventType);
activity.runOnUiThread(() -> {
if (type != null) {
eventColor = -1;
registerEventManualColorPreview.setBackgroundColor(type.color);
registerEventManualType.setText(type.name);
}
else {
eventColor = -1;
eventType = TYPE_UNDEFINED;
registerEventManualColorPreview.setBackgroundColor(COLOR_DEFAULT);
registerEventManualType.setText("");
}
});
});
}
else {
registerEventManualColorPreview.setBackgroundColor(COLOR_DEFAULT);
eventColor = -1;
}
/*if (dialogType == DIALOG_HOMEWORK) {
dialogView.findViewById(R.id.registerEventManualColorContainer).setVisibility(View.GONE);
registerEventManualType.setVisibility(View.GONE);
eventType = TYPE_HOMEWORK;
}
else {
}*/
updateButtonCaption();
if (editingEvent != null) {
this.editingEvent = editingEvent;
lessonDate = editingEvent.eventDate.clone();
lessonTeamId = editingEvent.teamId;
// check the (shared) checkbox if the event is already shared by someone
registerEventManualShare.setChecked(editingEvent.sharedBy != null);
// .. but disable the ability to un-share, if it's shared by someone else
registerEventManualShare.setEnabled(editingEvent.sharedBy == null || editingEvent.sharedBy.equals("self"));
registerEventManualShare.jumpDrawablesToCurrentState();
// show the notice text if the event is already shared
registerEventManualShareText.setVisibility(editingEvent.sharedBy != null ? View.VISIBLE : View.GONE);
if (editingEvent.sharedBy != null) {
// show the (change) notice if the event is shared by (self)
if (editingEvent.sharedBy.equals("self"))
registerEventManualShareText.setText(R.string.dialog_event_manual_share_will_change);
// otherwise show the (edit request) notice
else
registerEventManualShareText.setText(app.getString(R.string.dialog_event_manual_share_will_request, editingEvent.sharedByName));
}
updateButtonCaption(); // updates the lesson date and clears the time
lessonSubjectId = editingEvent.subjectId;
lessonTeacherId = editingEvent.teacherId;
lessonStartTime = editingEvent.startTime == null ? null : editingEvent.startTime.clone();
lessonSelected = true;
registerEventManualTeam.setText(ns(context.getString(R.string.dialog_event_manual_no_team), editingEvent.teamName));
registerEventManualTopic.setText(editingEvent.topic);
registerEventManualType.setText(editingEvent.typeName);
eventColor = editingEvent.getColor();
eventType = editingEvent.type;
registerEventManualColorPreview.setBackgroundColor(eventColor);
if (lessonSubjectId == -1) {
//lessonTeacherId = -1; // why tho?
registerEventManualLesson.setText(lessonStartTime == null ? app.getString(R.string.dialog_event_manual_all_day) : lessonStartTime.getStringHM());
}
else {
registerEventManualLesson.setText((lessonStartTime == null ? app.getString(R.string.dialog_event_manual_all_day) + "," : lessonStartTime.getStringHM())+" "+bs(editingEvent.subjectLongName));
}
}
else {
if (defaultDate != null) {
lessonDate = defaultDate.clone();
updateButtonCaption();
}
if (defaultDate != null && defaultTime != null) { // ONLY used when adding an event to the previously selected lesson
AsyncTask.execute(() -> {
LessonFull lesson = app.db.lessonDao().getByDateTimeWithoutChangesNow(profileId, defaultDate, defaultTime);
lessonTeacherId = lesson.teacherId;
lessonStartTime = lesson.startTime.clone();
lessonTeamId = lesson.teamId;
lessonSubjectId = lesson.subjectId;
lessonSelected = true;
activity.runOnUiThread(() -> {
registerEventManualTeam.setText(ns(context.getString(R.string.dialog_event_manual_no_team), lesson.teamName));
registerEventManualLesson.setText(lesson.startTime.getStringHM()+" "+bs(lesson.subjectLongName));
registerEventManualTeacher.setText(ns(context.getString(R.string.dialog_event_manual_no_teacher), lesson.teacherFullName));
registerEventManualSubject.setText(ns(context.getString(R.string.dialog_event_manual_no_subject), lesson.subjectLongName));
});
});
}
else {
AsyncTask.execute(() -> {
Team team = app.db.teamDao().getClassNow(profileId);
if (team != null) {
activity.runOnUiThread(() -> {
lessonTeamId = team.id;
registerEventManualTeam.setText(ns(context.getString(R.string.dialog_event_manual_no_team), team.name));
});
}
});
}
}
updateSubjectTeacher();
}
}

View File

@ -6,61 +6,85 @@ package pl.szczodrzynski.edziennik.ui.dialogs.timetable
import android.content.Intent import android.content.Intent
import android.view.View import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
import pl.szczodrzynski.edziennik.data.db.modules.timetable.LessonFull import pl.szczodrzynski.edziennik.data.db.modules.timetable.LessonFull
import pl.szczodrzynski.edziennik.databinding.DialogLessonDetailsBinding import pl.szczodrzynski.edziennik.databinding.DialogLessonDetailsBinding
import pl.szczodrzynski.edziennik.onClick
import pl.szczodrzynski.edziennik.setText import pl.szczodrzynski.edziennik.setText
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventDetailsDialog
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventListAdapter
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog
import pl.szczodrzynski.edziennik.ui.modules.timetable.v2.TimetableFragment import pl.szczodrzynski.edziennik.ui.modules.timetable.v2.TimetableFragment
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.Week import pl.szczodrzynski.edziennik.utils.models.Week
import kotlin.coroutines.CoroutineContext
class LessonDetailsDialog( class LessonDetailsDialog(
val activity: AppCompatActivity, val activity: AppCompatActivity,
val lesson: LessonFull, val lesson: LessonFull,
val onShowListener: ((tag: String) -> Unit)? = null, val onShowListener: ((tag: String) -> Unit)? = null,
val onDismissListener: ((tag: String) -> Unit)? = null val onDismissListener: ((tag: String) -> Unit)? = null
) { ) : CoroutineScope {
companion object { companion object {
private const val TAG = "LessonDetailsDialog" private const val TAG = "LessonDetailsDialog"
} }
private lateinit var app: App
private lateinit var b: DialogLessonDetailsBinding private lateinit var b: DialogLessonDetailsBinding
private lateinit var dialog: AlertDialog private lateinit var dialog: AlertDialog
private val job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
private lateinit var adapter: EventListAdapter
init { run { init { run {
if (activity.isFinishing) if (activity.isFinishing)
return@run return@run
onShowListener?.invoke(TAG) onShowListener?.invoke(TAG)
app = activity.applicationContext as App
b = DialogLessonDetailsBinding.inflate(activity.layoutInflater) b = DialogLessonDetailsBinding.inflate(activity.layoutInflater)
dialog = MaterialAlertDialogBuilder(activity) dialog = MaterialAlertDialogBuilder(activity)
.setView(b.root) .setView(b.root)
.setPositiveButton(R.string.close) { dialog, _ -> .setPositiveButton(R.string.close) { dialog, _ ->
dialog.dismiss() dialog.dismiss()
} }
.setNeutralButton(R.string.add) { _, _ -> .setNeutralButton(R.string.add, null)
EventManualDialog(
activity,
lesson.profileId,
lesson,
onShowListener = onShowListener,
onDismissListener = onDismissListener
)
}
.setOnDismissListener { .setOnDismissListener {
onDismissListener?.invoke(TAG) onDismissListener?.invoke(TAG)
} }
.show() .show()
dialog.getButton(AlertDialog.BUTTON_NEUTRAL)?.onClick {
EventManualDialog(
activity,
lesson.profileId,
defaultLesson = lesson,
onShowListener = onShowListener,
onDismissListener = onDismissListener
)
}
update() update()
}} }}
private fun update() { private fun update() {
b.lesson = lesson b.lesson = lesson
val lessonDate = lesson.displayDate ?: return val lessonDate = lesson.displayDate ?: return
val lessonTime = lesson.displayStartTime ?: return
b.lessonDate.text = Week.getFullDayName(lessonDate.weekDay) + ", " + lessonDate.formattedString b.lessonDate.text = Week.getFullDayName(lessonDate.weekDay) + ", " + lessonDate.formattedString
if (lesson.type >= Lesson.TYPE_SHIFTED_SOURCE) { if (lesson.type >= Lesson.TYPE_SHIFTED_SOURCE) {
@ -138,5 +162,49 @@ class LessonDetailsDialog(
if (lesson.type != Lesson.TYPE_CANCELLED && lesson.displayTeamId != null) { if (lesson.type != Lesson.TYPE_CANCELLED && lesson.displayTeamId != null) {
b.teamName = lesson.teamName b.teamName = lesson.teamName
} }
adapter = EventListAdapter(
activity,
onItemClick = {
Toast.makeText(activity, "Event clicked ${it.topic}", Toast.LENGTH_SHORT).show()
EventDetailsDialog(
activity,
it,
onShowListener = onShowListener,
onDismissListener = onDismissListener
)
},
onEventEditClick = {
EventManualDialog(
activity,
it.profileId,
editingEvent = it,
onShowListener = onShowListener,
onDismissListener = onDismissListener
)
}
)
app.db.eventDao().getAllByDateTime(lesson.profileId, lessonDate, lessonTime).observe(activity, Observer { events ->
adapter.items = events
if (b.eventsView.adapter == null) {
b.eventsView.adapter = adapter
b.eventsView.apply {
isNestedScrollingEnabled = false
setHasFixedSize(true)
layoutManager = LinearLayoutManager(context)
addItemDecoration(SimpleDividerItemDecoration(context))
}
}
adapter.notifyDataSetChanged()
if (events != null && events.isNotEmpty()) {
b.eventsView.visibility = View.VISIBLE
b.eventsNoData.visibility = View.GONE
} else {
b.eventsView.visibility = View.GONE
b.eventsNoData.visibility = View.VISIBLE
}
})
} }
} }

View File

@ -5,25 +5,34 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.navigation.NavController import kotlinx.coroutines.CoroutineScope
import androidx.navigation.Navigation import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.MainActivity
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.databinding.FragmentTemplateBinding import pl.szczodrzynski.edziennik.databinding.FragmentTemplateBinding
import pl.szczodrzynski.edziennik.utils.Themes import pl.szczodrzynski.edziennik.utils.Themes
import kotlin.coroutines.CoroutineContext
class TemplateFragment : Fragment() { class TemplateFragment : Fragment(), CoroutineScope {
companion object {
private const val TAG = "TemplateFragment"
}
private lateinit var app: App private lateinit var app: App
private lateinit var activity: MainActivity private lateinit var activity: MainActivity
private lateinit var b: FragmentTemplateBinding private lateinit var b: FragmentTemplateBinding
private val navController: NavController by lazy { Navigation.findNavController(b.root) }
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
// local/private variables go here
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as MainActivity?) ?: return null activity = (getActivity() as MainActivity?) ?: return null
if (context == null) context ?: return null
return null
app = activity.application as App app = activity.application as App
context!!.theme.applyStyle(Themes.appTheme, true) context!!.theme.applyStyle(Themes.appTheme, true)
if (app.profile == null) if (app.profile == null)

View File

@ -34,8 +34,7 @@ class NotificationsFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as MainActivity?) ?: return null activity = (getActivity() as MainActivity?) ?: return null
if (context == null) context ?: return null
return null
app = activity.application as App app = activity.application as App
context!!.theme.applyStyle(Themes.appTheme, true) context!!.theme.applyStyle(Themes.appTheme, true)
if (app.profile == null) if (app.profile == null)

View File

@ -53,7 +53,6 @@ import pl.szczodrzynski.edziennik.sync.SyncWorker;
import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog; import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog;
import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog; import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog;
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment; import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment;
import pl.szczodrzynski.edziennik.ui.modules.webpush.WebPushConfigActivity;
import pl.szczodrzynski.edziennik.utils.Themes; import pl.szczodrzynski.edziennik.utils.Themes;
import pl.szczodrzynski.edziennik.utils.Utils; import pl.szczodrzynski.edziennik.utils.Utils;
import pl.szczodrzynski.edziennik.utils.models.Date; import pl.szczodrzynski.edziennik.utils.models.Date;
@ -718,8 +717,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
.color(IconicsColor.colorInt(iconColor)) .color(IconicsColor.colorInt(iconColor))
) )
.setOnClickAction(() -> { .setOnClickAction(() -> {
Intent i = new Intent(activity, WebPushConfigActivity.class); activity.loadTarget(MainActivity.TARGET_WEB_PUSH, null);
startActivity(i);
}) })
); );

View File

@ -51,7 +51,6 @@ import pl.szczodrzynski.edziennik.MainActivity;
import pl.szczodrzynski.edziennik.R; import pl.szczodrzynski.edziennik.R;
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull; import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull;
import pl.szczodrzynski.edziennik.databinding.FragmentTimetableBinding; import pl.szczodrzynski.edziennik.databinding.FragmentTimetableBinding;
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialogOld;
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorDialog; import pl.szczodrzynski.edziennik.ui.modules.error.ErrorDialog;
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment; import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment;
import pl.szczodrzynski.edziennik.utils.SpannableHtmlTagHandler; import pl.szczodrzynski.edziennik.utils.SpannableHtmlTagHandler;
@ -113,10 +112,10 @@ public class TimetableFragment extends Fragment {
.itemsCallback((dialog, itemView, position, text) -> { .itemsCallback((dialog, itemView, position, text) -> {
switch (position) { switch (position) {
case 0: case 0:
new EventManualDialogOld(activity).show(app, null, displayingDate, null, EventManualDialogOld.DIALOG_EVENT); //new EventManualDialogOld(activity).show(app, null, displayingDate, null, EventManualDialogOld.DIALOG_EVENT);
break; break;
case 1: case 1:
new EventManualDialogOld(activity).show(app, null, displayingDate, null, EventManualDialogOld.DIALOG_HOMEWORK); //new EventManualDialogOld(activity).show(app, null, displayingDate, null, EventManualDialogOld.DIALOG_HOMEWORK);
break; break;
} }
}) })

View File

@ -53,8 +53,7 @@ class TimetableFragment : Fragment(), CoroutineScope {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as MainActivity?) ?: return null activity = (getActivity() as MainActivity?) ?: return null
if (context == null) context ?: return null
return null
app = activity.application as App app = activity.application as App
job = Job() job = Job()
context!!.theme.applyStyle(Themes.appTheme, true) context!!.theme.applyStyle(Themes.appTheme, true)

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-12-19.
*/
package pl.szczodrzynski.edziennik.ui.modules.webpush
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.szkolny.response.WebPushResponse
import pl.szczodrzynski.edziennik.databinding.WebPushBrowserItemBinding
import pl.szczodrzynski.edziennik.onClick
import pl.szczodrzynski.edziennik.setText
class WebPushBrowserAdapter(
val context: Context,
val onItemClick: ((browser: WebPushResponse.Browser) -> Unit)? = null,
val onUnpairButtonClick: ((browser: WebPushResponse.Browser) -> Unit)? = null
) : RecyclerView.Adapter<WebPushBrowserAdapter.ViewHolder>() {
private val app by lazy { context.applicationContext as App }
var items = listOf<WebPushResponse.Browser>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val view = WebPushBrowserItemBinding.inflate(inflater, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val browser = items[position]
val b = holder.b
onItemClick?.let { listener ->
b.root.onClick { listener(browser) }
}
b.browserName.text = browser.userAgent
b.datePaired.setText(R.string.web_push_date_paired_format, browser.dateRegistered)
onUnpairButtonClick?.let { listener ->
b.unpair.onClick { listener(browser) }
}
}
override fun getItemCount() = items.size
class ViewHolder(val b: WebPushBrowserItemBinding) : RecyclerView.ViewHolder(b.root)
}

View File

@ -0,0 +1,149 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-12-19.
*/
package pl.szczodrzynski.edziennik.ui.modules.webpush
import android.Manifest
import android.annotation.SuppressLint
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.coroutines.*
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
import pl.szczodrzynski.edziennik.data.api.szkolny.response.WebPushResponse
import pl.szczodrzynski.edziennik.databinding.WebPushFragmentBinding
import pl.szczodrzynski.edziennik.ui.dialogs.QrScannerDialog
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
import pl.szczodrzynski.edziennik.utils.Themes
import kotlin.coroutines.CoroutineContext
class WebPushFragment : Fragment(), CoroutineScope {
companion object {
private const val TAG = "TemplateFragment"
}
private lateinit var app: App
private lateinit var activity: MainActivity
private lateinit var b: WebPushFragmentBinding
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Main
private lateinit var adapter: WebPushBrowserAdapter
private val api by lazy {
SzkolnyApi(app)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
activity = (getActivity() as MainActivity?) ?: return null
context ?: 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 = WebPushFragmentBinding.inflate(inflater)
return b.root
}
@SuppressLint("DefaultLocale")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
// TODO check if app, activity, b can be null
if (app.profile == null || !isAdded)
return
b.scanQrCode.onClick {
val result = ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA)
if (result == PackageManager.PERMISSION_GRANTED) {
QrScannerDialog(activity, {
b.tokenEditText.setText(it.crc32().toString(36).toUpperCase())
pairBrowser(browserId = it)
})
} else {
ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.CAMERA), 1)
}
}
b.tokenAccept.onClick {
val pairToken = b.tokenEditText.text.toString().toUpperCase()
if (!"[0-9A-Z]{3,13}".toRegex().matches(pairToken)) {
b.tokenLayout.error = app.getString(R.string.web_push_token_invalid)
return@onClick
}
b.tokenLayout.error = null
b.tokenEditText.setText(pairToken)
pairBrowser(pairToken = pairToken)
}
adapter = WebPushBrowserAdapter(
activity,
onItemClick = null,
onUnpairButtonClick = {
unpairBrowser(it.browserId)
}
)
launch {
val browsers = withContext(Dispatchers.Default) {
api.listBrowsers()
}
updateBrowserList(browsers)
}
}
private fun updateBrowserList(browsers: List<WebPushResponse.Browser>) {
adapter.items = browsers
if (b.browsersView.adapter == null) {
b.browsersView.adapter = adapter
b.browsersView.apply {
isNestedScrollingEnabled = false
setHasFixedSize(true)
layoutManager = LinearLayoutManager(context)
addItemDecoration(SimpleDividerItemDecoration(context))
}
}
adapter.notifyDataSetChanged()
if (browsers.isNotEmpty()) {
b.browsersView.visibility = View.VISIBLE
b.browsersNoData.visibility = View.GONE
} else {
b.browsersView.visibility = View.GONE
b.browsersNoData.visibility = View.VISIBLE
}
}
private fun pairBrowser(browserId: String? = null, pairToken: String? = null) {
b.scanQrCode.isEnabled = false
b.tokenAccept.isEnabled = false
b.tokenEditText.isEnabled = false
b.tokenEditText.clearFocus()
launch {
val browsers = withContext(Dispatchers.Default) {
api.pairBrowser(browserId, pairToken)
}
b.scanQrCode.isEnabled = true
b.tokenAccept.isEnabled = true
b.tokenEditText.isEnabled = true
updateBrowserList(browsers)
}
}
private fun unpairBrowser(browserId: String) {
launch {
val browsers = withContext(Dispatchers.Default) {
api.unpairBrowser(browserId)
}
updateBrowserList(browsers)
}
}
}

View File

@ -0,0 +1,52 @@
<!--
~ Copyright (c) Kuba Szczodrzyński 2019-12-19.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="64dp"
android:viewportWidth="64"
android:viewportHeight="64">
<path
android:pathData="M56,46.668L8,46.668L8,9.332C8,8.5938 8.5977,8 9.332,8L54.668,8C55.4063,8 56,8.5938 56,9.332Z"
android:fillColor="#455A64"
android:fillAlpha="1"
android:fillType="nonZero"
android:strokeColor="#00000000"/>
<path
android:pathData="M10.668,10.668L53.332,10.668L53.332,37.332L10.668,37.332Z"
android:fillColor="#BBDEFB"
android:fillAlpha="1"
android:fillType="nonZero"
android:strokeColor="#00000000"/>
<path
android:pathData="M0,53.332L64,53.332L64,56L0,56Z"
android:fillColor="#B0BEC5"
android:fillAlpha="1"
android:fillType="nonZero"
android:strokeColor="#00000000"/>
<path
android:pathData="M56,40L8,40L0,53.332L64,53.332Z"
android:fillColor="#CFD8DC"
android:fillAlpha="1"
android:fillType="nonZero"
android:strokeColor="#00000000"/>
<path
android:pathData="M10.668,42.668L53.332,42.668L57.332,50.668L6.668,50.668Z"
android:fillColor="#546E7A"
android:fillAlpha="1"
android:fillType="nonZero"
android:strokeColor="#00000000"/>
<path
android:pathData="M22.0586,50.668L21.332,53.332L42.668,53.332L41.9414,50.668Z"
android:fillColor="#90A4AE"
android:fillAlpha="1"
android:fillType="nonZero"
android:strokeColor="#00000000"/>
<path
android:pathData="M37.332,24C37.332,21.668 38.668,21.332 38.668,21.332L45.332,21.332C44.3047,18.9805 41.3984,17.332 38.668,17.332C35.9336,17.332 33.5938,18.9805 32.5625,21.332L21.332,21.332C19.8594,21.332 18.668,22.5273 18.668,24C18.668,25.4727 19.8594,26.668 21.332,26.668L32.5625,26.668C33.5938,29.0195 35.9336,30.668 38.668,30.668C41.3984,30.668 44.3047,29.0195 45.332,26.668L38.668,26.668C38.668,26.668 37.332,26.332 37.332,24Z"
android:fillColor="#1976D2"
android:fillAlpha="1"
android:fillType="nonZero"
android:strokeColor="#00000000"/>
</vector>

View File

@ -8,25 +8,25 @@
<data> <data>
</data> </data>
<ScrollView <androidx.core.widget.NestedScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<LinearLayout <LinearLayout
android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingTop="24dp" android:orientation="vertical"
android:paddingLeft="16dp" android:paddingLeft="16dp"
android:paddingTop="24dp"
android:paddingRight="16dp"> android:paddingRight="16dp">
<TextView <TextView
android:id="@+id/dayDate" android:id="@+id/dayDate"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textIsSelectable="true"
android:textAppearance="@style/NavView.TextView.Title"
android:layout_marginLeft="8dp" android:layout_marginLeft="8dp"
android:layout_marginRight="8dp" android:layout_marginRight="8dp"
android:textAppearance="@style/NavView.TextView.Title"
android:textIsSelectable="true"
tools:text="wtorek, 17 grudnia" /> tools:text="wtorek, 17 grudnia" />
<include <include
@ -34,10 +34,10 @@
layout="@layout/row_lesson_change_item" layout="@layout/row_lesson_change_item"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:layout_marginLeft="8dp" android:layout_marginLeft="8dp"
android:layout_marginTop="5dp"
android:layout_marginRight="8dp" android:layout_marginRight="8dp"
android:layout_marginBottom="5dp"
android:visibility="gone" android:visibility="gone"
tools:visibility="visible" /> tools:visibility="visible" />
@ -78,7 +78,7 @@
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Możesz wpisać wydarzenie ręcznie, używając przycisku Dodaj." android:text="@string/dialog_no_events_hint"
android:gravity="center" android:gravity="center"
android:textStyle="italic"/> android:textStyle="italic"/>
@ -90,9 +90,9 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:clipToPadding="false" android:clipToPadding="false"
tools:visibility="gone" tools:visibility="visible"
tools:listitem="@layout/event_list_item" /> tools:listitem="@layout/event_list_item" />
</LinearLayout> </LinearLayout>
</ScrollView> </androidx.core.widget.NestedScrollView>
</layout> </layout>

View File

@ -0,0 +1,154 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2019-12-18.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View"/>
<import type="pl.szczodrzynski.edziennik.App"/>
<variable
name="event"
type="pl.szczodrzynski.edziennik.data.db.modules.events.EventFull" />
<variable name="eventShared" type="boolean" />
<variable name="eventOwn" type="boolean" />
<variable name="details" type="java.lang.CharSequence" />
<variable name="monthName" type="String" />
</data>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="24dp"
android:paddingTop="24dp"
android:paddingRight="24dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:orientation="horizontal">
<View
android:id="@+id/typeColor"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:background="@drawable/unread_red_circle" />
<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="@{event.typeName}"
android:textIsSelectable="true"
android:textAppearance="@style/NavView.TextView.Title"
android:visibility="@{event.typeName == null ? View.GONE : View.VISIBLE}"
tools:text="sprawdzian" />
<TextView
android:id="@+id/lessonDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textIsSelectable="true"
android:textAppearance="@style/NavView.TextView.Subtitle"
android:text="@{details}"
android:visibility="@{details == null ? View.GONE : View.VISIBLE}"
tools:text="język angielski • 2B3T a2"
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="@{event.startTime == null ? @string/event_all_day : event.startTime.stringHM}"
tools:text="14:50"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
android:text="@{Integer.toString(event.eventDate.day)}"
android:textSize="36sp"
tools:text="14" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{monthName}"
tools:text="listopada" />
</LinearLayout>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/NavView.TextView.Helper"
android:text="@string/dialog_event_details_teacher"
android:visibility="@{event.teacherFullName != null ? View.VISIBLE : View.GONE}"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{event.teacherFullName}"
android:textIsSelectable="true"
android:visibility="@{event.teacherFullName != 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_event_details_added_by"/>
<com.mikepenz.iconics.view.IconicsTextView
android:id="@+id/addedBy"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textIsSelectable="true"
tools:text="18 grudnia, 23:17 przez Janósz Kowalski" />
<!--<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="4dp"
android:background="@color/dividerColor"/>-->
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textAppearance="@style/NavView.TextView.Helper"
android:text="@string/dialog_event_details_topic"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{event.topic}"
android:textIsSelectable="true"
android:textAppearance="@style/NavView.TextView.Medium"
tools:text="Rozdział II: Panowanie Piastów i Jagiellonów.Przeniesiony z 11 grudnia." />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</layout>

View File

@ -21,20 +21,24 @@
<variable name="oldTeamName" type="String" /> <variable name="oldTeamName" type="String" />
<variable name="teamName" type="String" /> <variable name="teamName" type="String" />
</data> </data>
<ScrollView <androidx.core.widget.NestedScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<LinearLayout <LinearLayout
android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="24dp"> android:orientation="vertical"
android:paddingLeft="16dp"
android:paddingTop="24dp"
android:paddingRight="16dp">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:layout_marginLeft="8dp"
android:baselineAligned="false"> android:layout_marginRight="8dp"
android:baselineAligned="false"
android:orientation="horizontal">
<LinearLayout <LinearLayout
android:orientation="vertical" android:orientation="vertical"
@ -110,7 +114,9 @@
android:id="@+id/shiftedLayout" android:id="@+id/shiftedLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:layout_marginRight="8dp"
android:baselineAligned="false" android:baselineAligned="false"
android:gravity="center_vertical" android:gravity="center_vertical"
android:orientation="horizontal"> android:orientation="horizontal">
@ -129,99 +135,184 @@
style="@style/Widget.MaterialComponents.Button.OutlinedButton" style="@style/Widget.MaterialComponents.Button.OutlinedButton"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Przejdź" /> android:text="@string/dialog_lesson_go_to_button" />
</LinearLayout> </LinearLayout>
<TextView <LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginTop="8dp"
android:layout_marginRight="8dp"
android:baselineAligned="false"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:orientation="vertical"
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="@string/dialog_lesson_details_teacher" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/NavView.TextView.Helper"
android:text="@{oldTeacherName}"
android:textIsSelectable="true"
android:singleLine="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" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
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="@string/dialog_lesson_details_team" />
<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" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:baselineAligned="false"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:visibility="@{classroom != null || oldClassroom != null ? View.VISIBLE : View.GONE}">
<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" />
<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" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:visibility="@{App.devMode ? View.VISIBLE : View.GONE}">
<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_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"
tools:text="12345" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/eventsNoData"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawableTop="@drawable/ic_no_events"
android:drawablePadding="16dp"
android:fontFamily="sans-serif-light"
android:text="@string/dialog_lesson_no_events"
android:textSize="24sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/dialog_no_events_hint"
android:gravity="center"
android:textStyle="italic"/>
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/eventsView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:textAppearance="@style/NavView.TextView.Helper" android:clipToPadding="false"
android:text="@string/dialog_lesson_details_teacher" tools:visibility="visible"
android:visibility="@{teacherName != null || oldTeacherName != null ? View.VISIBLE : View.GONE}"/> tools:listitem="@layout/event_list_item" />
<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> </LinearLayout>
</ScrollView> </androidx.core.widget.NestedScrollView>
</layout> </layout>

View File

@ -45,12 +45,13 @@
<TextView <TextView
android:id="@+id/topic" android:id="@+id/topic"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:textAppearance="@style/NavView.TextView.Medium" android:textAppearance="@style/NavView.TextView.Medium"
android:maxLines="3" android:maxLines="3"
tools:text="Rozdział II: Panowanie Piastów i Jagiellonów.Przeniesiony z 11 grudnia." /> android:ellipsize="end"
tools:text="Rozdział II: Panowanie Piastów i Jagiellonów.Przeniesiony z 11 grudnia. Nie wiem co się dzieje w tym roku nie będzie już religii w szkołach podstawowych w Polsce i Europie zachodniej Afryki" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/editButton" android:id="@+id/editButton"
@ -64,13 +65,13 @@
</LinearLayout> </LinearLayout>
<TextView <com.mikepenz.iconics.view.IconicsTextView
android:id="@+id/addedBy" android:id="@+id/addedBy"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textAppearance="@style/NavView.TextView.Helper" android:textAppearance="@style/NavView.TextView.Helper"
android:singleLine="true" android:singleLine="true"
android:ellipsize="middle" android:ellipsize="middle"
android:text="Udostępniono 10 grudnia przez Ktoś Z Twojej Klasy • 2B3T" /> tools:text="Udostępniono 10 grudnia przez Ktoś Z Twojej Klasy • 2B3T" />
</LinearLayout> </LinearLayout>
</layout> </layout>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2019-12-19.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:orientation="vertical"
android:background="?selectableItemBackground">
</LinearLayout>
</layout>

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2019-12-19.
-->
<layout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:padding="8dp"
android:orientation="horizontal"
android:background="?selectableItemBackground"
android:baselineAligned="false">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/browserName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/NavView.TextView.Medium"
tools:text="Firefox 71.0 @ Windows 7 64-bit"/>
<TextView
android:id="@+id/datePaired"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="Połączono 2019-12-12 19:54:09"/>
</LinearLayout>
<Button
android:id="@+id/unpair"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:text="@string/web_push_unpair_button" />
</LinearLayout>
</layout>

View File

@ -0,0 +1,111 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) Kuba Szczodrzyński 2019-12-19.
-->
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Przekazywanie powiadomień pozwala na połączenie komputera, na którym będą pokazywane powiadomienia otrzymane w aplikacji Szkolny.eu na telefonie.\n\nDzięki temu będziesz zawsze wiedział wszystko na bieżąco, nie patrząc nawet na swój telefon."/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:fontFamily="sans-serif-light"
android:text="Jak połączyć komputer z aplikacją?"
android:textSize="24sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="1. Na komputerze otwórz stronę http://szkolny.eu/wp\n2. Zezwól stronie na wyświetlanie powiadomień dot. danych z dziennika.\n3. Kliknij przycisk &quot;Skanuj&quot; poniżej lub przepisz token ze strony."/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:fontFamily="sans-serif-light"
android:text="Sparuj przeglądarkę"
android:textSize="24sp" />
<Button
android:id="@+id/scanQrCode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Skanuj kod QR" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tokenLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="Token">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/tokenEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="1A22IT" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/tokenAccept"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:text="OK" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:fontFamily="sans-serif-light"
android:text="Połączone przeglądarki"
android:textSize="24sp" />
<TextView
android:id="@+id/browsersNoData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="8dp"
android:drawableTop="@drawable/ic_web_push_no_browsers"
android:drawablePadding="16dp"
android:fontFamily="sans-serif-light"
android:text="Brak połączonych przeglądarek"
android:textSize="18sp"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/browsersView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:clipToPadding="false"
tools:visibility="visible"
tools:listitem="@layout/web_push_browser_item" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</layout>

View File

@ -30,6 +30,21 @@
<item>grudzień</item> <item>grudzień</item>
</array> </array>
<array name="months_day_of_array">
<item>stycznia</item>
<item>lutego</item>
<item>marca</item>
<item>kwietnia</item>
<item>maja</item>
<item>czerwca</item>
<item>lipca</item>
<item>sierpnia</item>
<item>września</item>
<item>października</item>
<item>listopada</item>
<item>grudnia</item>
</array>
<array name="main_menu_add_options"> <array name="main_menu_add_options">
<item>Wydarzenie</item> <item>Wydarzenie</item>
<item>Zadanie domowe</item> <item>Zadanie domowe</item>
@ -1070,10 +1085,28 @@
<string name="event_list_added_by_format">Dodano %1$s przez %2$s%3$s</string> <string name="event_list_added_by_format">Dodano %1$s przez %2$s%3$s</string>
<string name="event_list_added_by_unknown_format">Dodano %1$s%3$s</string> <string name="event_list_added_by_unknown_format">Dodano %1$s%3$s</string>
<string name="event_list_added_by_self_format">Dodano %1$s przez Ciebie%3$s</string> <string name="event_list_added_by_self_format">Dodano %1$s przez Ciebie%3$s</string>
<string name="event_list_shared_by_format">Udostępniono %1$s przez %2$s%3$s</string> <string name="event_list_shared_by_format">{cmd-share-variant} %1$s przez %2$s%3$s</string>
<string name="event_list_shared_by_self_format">Udostępniono %1$s przez Ciebie%3$s</string> <string name="event_list_shared_by_self_format">{cmd-share-variant} %1$s przez Ciebie%3$s</string>
<string name="settings_theme_snowfall_text">Pada śnieg, pada śnieg</string> <string name="settings_theme_snowfall_text">Pada śnieg, pada śnieg</string>
<string name="settings_theme_snowfall_subtext">Dzwonią dzwonki sań</string> <string name="settings_theme_snowfall_subtext">Dzwonią dzwonki sań</string>
<string name="dialog_day_no_events">Brak wydarzeń tego dnia.</string> <string name="dialog_day_no_events">Brak wydarzeń tego dnia.</string>
<string name="dialog_day_date_format">%s, %s</string> <string name="dialog_day_date_format">%s, %s</string>
<string name="dialog_lesson_go_to_button">Przejdź</string>
<string name="dialog_no_events_hint">Możesz wpisać wydarzenie ręcznie, używając przycisku Dodaj.</string>
<string name="dialog_lesson_no_events">Brak wydarzeń na tej lekcji.</string>
<string name="dialog_event_details_teacher">Nauczyciel</string>
<string name="dialog_event_details_subject">Przedmiot</string>
<string name="dialog_event_details_team">Grupa</string>
<string name="dialog_event_details_added_by">Dodano</string>
<string name="dialog_event_details_topic">Temat</string>
<string name="event_details_added_by_format">%1$s przez %2$s</string>
<string name="event_details_added_by_unknown_format">%1$s</string>
<string name="event_details_added_by_self_format">%1$s przez Ciebie</string>
<string name="event_details_shared_by_format">{cmd-share-variant} %1$s przez %2$s</string>
<string name="event_details_shared_by_self_format">{cmd-share-variant} %1$s przez Ciebie</string>
<string name="web_push_token_invalid">Token nie wygląda na prawidłowy</string>
<string name="menu_web_push">Przekazywanie powiadomień</string>
<string name="qr_scanner_dialog_title">Skanuj kod QR</string>
<string name="web_push_unpair_button">Odłącz</string>
<string name="web_push_date_paired_format">Połączono %s</string>
</resources> </resources>

View File

@ -5,8 +5,8 @@ buildscript {
kotlin_version = '1.3.50' kotlin_version = '1.3.50'
release = [ release = [
versionName: "3.9.15-dev", versionName: "3.9.16-dev",
versionCode: 3091500 versionCode: 3091600
] ]
setup = [ setup = [