mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2025-06-15 07:00:20 +02:00
Compare commits
19 Commits
v3.9.5-dev
...
v3.9.7-dev
Author | SHA1 | Date | |
---|---|---|---|
1c6815f708 | |||
9a20511935 | |||
965f5e73d9 | |||
13b58a1d56 | |||
0a3261b8b3 | |||
dbdfc7fdd8 | |||
56062f5bfa | |||
0cbba2eb45 | |||
aa84356dd6 | |||
efaad0a4dd | |||
71015c0137 | |||
85b5667a7e | |||
dfdc6817a1 | |||
058345b9c9 | |||
831b7876b4 | |||
729cf6f08e | |||
860a16b32d | |||
9f871c077b | |||
a8f89abf7d |
@ -105,6 +105,11 @@
|
||||
android:excludeFromRecents="true"
|
||||
android:noHistory="true"
|
||||
android:theme="@style/AppTheme.NoDisplay" />
|
||||
<activity android:name=".widgets.timetable.LessonDialogActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:excludeFromRecents="true"
|
||||
android:noHistory="true"
|
||||
android:theme="@style/AppTheme.NoDisplay" />
|
||||
<activity
|
||||
android:name=".ui.modules.settings.SettingsLicenseActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
|
@ -68,11 +68,6 @@ import me.leolin.shortcutbadger.ShortcutBadger;
|
||||
import okhttp3.ConnectionSpec;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.TlsVersion;
|
||||
import pl.szczodrzynski.edziennik.data.api.Edziennik;
|
||||
import pl.szczodrzynski.edziennik.data.api.Iuczniowie;
|
||||
import pl.szczodrzynski.edziennik.data.api.Librus;
|
||||
import pl.szczodrzynski.edziennik.data.api.Mobidziennik;
|
||||
import pl.szczodrzynski.edziennik.data.api.Vulcan;
|
||||
import pl.szczodrzynski.edziennik.data.db.AppDb;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.debuglog.DebugLog;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore;
|
||||
@ -141,12 +136,6 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
public PersistentCookieJar cookieJar;
|
||||
public OkHttpClient http;
|
||||
public OkHttpClient httpLazy;
|
||||
//public Jakdojade apiJakdojade;
|
||||
public Edziennik apiEdziennik;
|
||||
public Mobidziennik apiMobidziennik;
|
||||
public Iuczniowie apiIuczniowie;
|
||||
public Librus apiLibrus;
|
||||
public Vulcan apiVulcan;
|
||||
|
||||
public SharedPreferences appSharedPrefs; // sharedPreferences for APPCONFIG + JOBS STORE
|
||||
public AppConfig appConfig; // APPCONFIG: common for all profiles
|
||||
@ -204,12 +193,6 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
db = AppDb.getDatabase(this);
|
||||
gson = new Gson();
|
||||
networkUtils = new NetworkUtils(this);
|
||||
apiEdziennik = new Edziennik(this);
|
||||
//apiJakdojade = new Jakdojade(this);
|
||||
apiMobidziennik = new Mobidziennik(this);
|
||||
apiIuczniowie = new Iuczniowie(this);
|
||||
apiLibrus = new Librus(this);
|
||||
apiVulcan = new Vulcan(this);
|
||||
|
||||
Iconics.init(getApplicationContext());
|
||||
Iconics.registerFont(SzkolnyFont.INSTANCE);
|
||||
|
@ -95,6 +95,15 @@ fun String.swapFirstLastName(): String {
|
||||
}
|
||||
}
|
||||
|
||||
fun String.getFirstLastName(): Pair<String, String>? {
|
||||
return this.split(" ").let {
|
||||
if (it.size >= 2) Pair(it[0], it[1])
|
||||
else null
|
||||
}
|
||||
}
|
||||
|
||||
fun String.getLastFirstName() = this.getFirstLastName()
|
||||
|
||||
fun changeStringCase(s: String): String {
|
||||
val delimiters = " '-/"
|
||||
val sb = StringBuilder()
|
||||
@ -153,8 +162,9 @@ fun colorFromName(context: Context, name: String?): Int {
|
||||
return context.getColorFromRes(color)
|
||||
}
|
||||
|
||||
fun MutableList<out Profile>.filterOutArchived() {
|
||||
fun MutableList<Profile>.filterOutArchived(): MutableList<Profile> {
|
||||
this.removeAll { it.archived }
|
||||
return this
|
||||
}
|
||||
|
||||
fun Activity.isStoragePermissionGranted(): Boolean {
|
||||
@ -435,4 +445,4 @@ fun <T> LiveData<T>.observeOnce(lifecycleOwner: LifecycleOwner, observer: Observ
|
||||
removeObserver(this)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -38,18 +38,20 @@ import pl.droidsonroids.gif.GifDrawable
|
||||
import pl.szczodrzynski.edziennik.App.APP_URL
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.task.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface.*
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata.*
|
||||
import pl.szczodrzynski.edziennik.databinding.ActivitySzkolnyBinding
|
||||
import pl.szczodrzynski.edziennik.network.ServerRequest
|
||||
import pl.szczodrzynski.edziennik.sync.AppManagerDetectedEvent
|
||||
import pl.szczodrzynski.edziennik.sync.SyncWorker
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.sync.SyncViewListDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.agenda.AgendaFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.announcements.AnnouncementsFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.attendance.AttendanceFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.DebugFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.behaviour.BehaviourFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar
|
||||
import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.feedback.HelpFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.GradesFragment
|
||||
@ -214,6 +216,7 @@ class MainActivity : AppCompatActivity() {
|
||||
val navView: NavView by lazy { b.navView }
|
||||
val drawer: NavDrawer by lazy { navView.drawer }
|
||||
val bottomSheet: NavBottomSheet by lazy { navView.bottomSheet }
|
||||
val errorSnackbar: ErrorSnackbar by lazy { ErrorSnackbar(this) }
|
||||
|
||||
val swipeRefreshLayout: SwipeRefreshLayoutNoTouch by lazy { b.swipeRefreshLayout }
|
||||
|
||||
@ -246,6 +249,8 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
setContentView(b.root)
|
||||
|
||||
errorSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar)
|
||||
|
||||
navLoading = true
|
||||
|
||||
b.navView.apply {
|
||||
@ -371,6 +376,11 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
b.swipeRefreshLayout.isEnabled = true
|
||||
b.swipeRefreshLayout.setOnRefreshListener { this.syncCurrentFeature() }
|
||||
b.swipeRefreshLayout.setColorSchemeResources(
|
||||
R.color.md_blue_500,
|
||||
R.color.md_amber_500,
|
||||
R.color.md_green_500
|
||||
)
|
||||
|
||||
isStoragePermissionGranted()
|
||||
|
||||
@ -464,7 +474,7 @@ class MainActivity : AppCompatActivity() {
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_sync)
|
||||
.withOnClickListener(View.OnClickListener {
|
||||
bottomSheet.close()
|
||||
app.apiEdziennik.guiSyncFeature(app, this, App.profileId, R.string.sync_dialog_title, R.string.sync_dialog_text, R.string.sync_done, fragmentToFeature(navTargetId))
|
||||
SyncViewListDialog(this, navTargetId)
|
||||
}),
|
||||
BottomSheetSeparatorItem(false),
|
||||
BottomSheetPrimaryItem(false)
|
||||
@ -573,7 +583,12 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onSyncErrorEvent(event: ApiTaskErrorEvent) {
|
||||
|
||||
navView.toolbar.apply {
|
||||
subtitleFormat = R.string.toolbar_subtitle
|
||||
subtitleFormatWithUnread = R.plurals.toolbar_subtitle_with_unread
|
||||
subtitle = "Gotowe"
|
||||
}
|
||||
errorSnackbar.addError(event.error).show()
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||
fun onAppManagerDetectedEvent(event: AppManagerDetectedEvent) {
|
||||
@ -605,22 +620,7 @@ class MainActivity : AppCompatActivity() {
|
||||
.setCancelable(false)
|
||||
.show()
|
||||
}
|
||||
private fun fragmentToFeature(currentFragment: Int): Int {
|
||||
return when (currentFragment) {
|
||||
DRAWER_ITEM_TIMETABLE -> FEATURE_TIMETABLE
|
||||
DRAWER_ITEM_AGENDA -> FEATURE_AGENDA
|
||||
DRAWER_ITEM_GRADES -> FEATURE_GRADES
|
||||
DRAWER_ITEM_HOMEWORK -> FEATURE_HOMEWORK
|
||||
DRAWER_ITEM_BEHAVIOUR -> FEATURE_NOTICES
|
||||
DRAWER_ITEM_ATTENDANCE -> FEATURE_ATTENDANCE
|
||||
DRAWER_ITEM_MESSAGES -> when (MessagesFragment.pageSelection) {
|
||||
1 -> FEATURE_MESSAGES_OUTBOX
|
||||
else -> FEATURE_MESSAGES_INBOX
|
||||
}
|
||||
DRAWER_ITEM_ANNOUNCEMENTS -> FEATURE_ANNOUNCEMENTS
|
||||
else -> FEATURE_ALL
|
||||
}
|
||||
}
|
||||
|
||||
private fun fragmentToSyncName(currentFragment: Int): Int {
|
||||
return when (currentFragment) {
|
||||
DRAWER_ITEM_TIMETABLE -> R.string.sync_feature_timetable
|
||||
@ -1043,7 +1043,7 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
loadTarget(DRAWER_ITEM_SETTINGS, null)
|
||||
} else if (item.itemId == 2) {
|
||||
app.apiEdziennik.guiRemoveProfile(this@MainActivity, profileId, profile.name?.getText(this).toString())
|
||||
ProfileRemoveDialog(this, profileId, profile.name?.getText(this)?.toString() ?: "?")
|
||||
}
|
||||
true
|
||||
}
|
||||
|
@ -1,450 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetProvider;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
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 java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.task.EdziennikTask;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.ItemWidgetTimetableModel;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Week;
|
||||
import pl.szczodrzynski.edziennik.widgets.WidgetConfig;
|
||||
import pl.szczodrzynski.edziennik.widgets.timetable.LessonDetailsActivity;
|
||||
import pl.szczodrzynski.edziennik.widgets.timetable.WidgetTimetableService;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.ExtensionsKt.filterOutArchived;
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.events.Event.TYPE_HOMEWORK;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.bs;
|
||||
|
||||
|
||||
public class WidgetTimetable extends AppWidgetProvider {
|
||||
|
||||
|
||||
public static final String ACTION_SYNC_DATA = "ACTION_SYNC_DATA";
|
||||
private static final String TAG = "WidgetTimetable";
|
||||
private static int modeInt = 0;
|
||||
|
||||
public WidgetTimetable() {
|
||||
// Start the worker thread
|
||||
//HandlerThread sWorkerThread = new HandlerThread("WidgetTimetable-worker");
|
||||
//sWorkerThread.start();
|
||||
//Handler sWorkerQueue = new Handler(sWorkerThread.getLooper());
|
||||
}
|
||||
|
||||
public static SparseArray<List<ItemWidgetTimetableModel>> timetables = null;
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (ACTION_SYNC_DATA.equals(intent.getAction())) {
|
||||
EdziennikTask.Companion.sync().enqueue(context);
|
||||
}
|
||||
super.onReceive(context, intent);
|
||||
}
|
||||
|
||||
public static PendingIntent getPendingSelfIntent(Context context, String action) {
|
||||
Intent intent = new Intent(context, WidgetTimetable.class);
|
||||
intent.setAction(action);
|
||||
return getPendingSelfIntent(context, intent);
|
||||
}
|
||||
public static PendingIntent getPendingSelfIntent(Context context, Intent intent) {
|
||||
return PendingIntent.getBroadcast(context, 0, intent, 0);
|
||||
}
|
||||
|
||||
public static Bitmap drawableToBitmap (Drawable drawable) {
|
||||
|
||||
if (drawable instanceof BitmapDrawable) {
|
||||
return ((BitmapDrawable)drawable).getBitmap();
|
||||
}
|
||||
|
||||
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
||||
drawable.draw(canvas);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
|
||||
ComponentName thisWidget = new ComponentName(context, WidgetTimetable.class);
|
||||
|
||||
timetables = new SparseArray<>();
|
||||
//timetables.clear();
|
||||
|
||||
App app = (App)context.getApplicationContext();
|
||||
|
||||
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
|
||||
// There may be multiple widgets active, so update all of them
|
||||
for (int appWidgetId : allWidgetIds) {
|
||||
|
||||
//d(TAG, "thr "+Thread.currentThread().getName());
|
||||
|
||||
WidgetConfig widgetConfig = app.appConfig.widgetTimetableConfigs.get(appWidgetId);
|
||||
if (widgetConfig == null) {
|
||||
widgetConfig = new WidgetConfig(app.profileFirstId());
|
||||
app.appConfig.widgetTimetableConfigs.put(appWidgetId, widgetConfig);
|
||||
app.appConfig.savePending = true;
|
||||
}
|
||||
|
||||
RemoteViews views;
|
||||
if (widgetConfig.bigStyle) {
|
||||
views = new RemoteViews(context.getPackageName(), widgetConfig.darkTheme ? R.layout.widget_timetable_dark_big : R.layout.widget_timetable_big);
|
||||
}
|
||||
else {
|
||||
views = new RemoteViews(context.getPackageName(), widgetConfig.darkTheme ? R.layout.widget_timetable_dark : R.layout.widget_timetable);
|
||||
}
|
||||
|
||||
PorterDuff.Mode mode = PorterDuff.Mode.DST_IN;
|
||||
/*if (widgetConfig.darkTheme) {
|
||||
switch (modeInt) {
|
||||
case 0:
|
||||
mode = PorterDuff.Mode.ADD;
|
||||
d(TAG, "ADD");
|
||||
break;
|
||||
case 1:
|
||||
mode = PorterDuff.Mode.DST_ATOP;
|
||||
d(TAG, "DST_ATOP");
|
||||
break;
|
||||
case 2:
|
||||
mode = PorterDuff.Mode.DST_IN;
|
||||
d(TAG, "DST_IN");
|
||||
break;
|
||||
case 3:
|
||||
mode = PorterDuff.Mode.DST_OUT;
|
||||
d(TAG, "DST_OUT");
|
||||
break;
|
||||
case 4:
|
||||
mode = PorterDuff.Mode.DST_OVER;
|
||||
d(TAG, "DST_OVER");
|
||||
break;
|
||||
case 5:
|
||||
mode = PorterDuff.Mode.LIGHTEN;
|
||||
d(TAG, "LIGHTEN");
|
||||
break;
|
||||
case 6:
|
||||
mode = PorterDuff.Mode.MULTIPLY;
|
||||
d(TAG, "MULTIPLY");
|
||||
break;
|
||||
case 7:
|
||||
mode = PorterDuff.Mode.OVERLAY;
|
||||
d(TAG, "OVERLAY");
|
||||
break;
|
||||
case 8:
|
||||
mode = PorterDuff.Mode.SCREEN;
|
||||
d(TAG, "SCREEN");
|
||||
break;
|
||||
case 9:
|
||||
mode = PorterDuff.Mode.SRC_ATOP;
|
||||
d(TAG, "SRC_ATOP");
|
||||
break;
|
||||
case 10:
|
||||
mode = PorterDuff.Mode.SRC_IN;
|
||||
d(TAG, "SRC_IN");
|
||||
break;
|
||||
case 11:
|
||||
mode = PorterDuff.Mode.SRC_OUT;
|
||||
d(TAG, "SRC_OUT");
|
||||
break;
|
||||
case 12:
|
||||
mode = PorterDuff.Mode.SRC_OVER;
|
||||
d(TAG, "SRC_OVER");
|
||||
break;
|
||||
case 13:
|
||||
mode = PorterDuff.Mode.XOR;
|
||||
d(TAG, "XOR");
|
||||
break;
|
||||
default:
|
||||
modeInt = 0;
|
||||
mode = PorterDuff.Mode.ADD;
|
||||
d(TAG, "ADD");
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
|
||||
// this code seems to crash the launcher on >= P
|
||||
float transparency = widgetConfig.opacity; //0...1
|
||||
long colorFilter = 0x01000000L * (long) (255f * transparency);
|
||||
try {
|
||||
final Method[] declaredMethods = Class.forName("android.widget.RemoteViews").getDeclaredMethods();
|
||||
final int len = declaredMethods.length;
|
||||
if (len > 0) {
|
||||
for (int m = 0; m < len; m++) {
|
||||
final Method method = declaredMethods[m];
|
||||
if (method.getName().equals("setDrawableParameters")) {
|
||||
method.setAccessible(true);
|
||||
method.invoke(views, R.id.widgetTimetableListView, true, -1, (int) colorFilter, mode, -1);
|
||||
method.invoke(views, R.id.widgetTimetableHeader, true, -1, (int) colorFilter, mode, -1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
Intent refreshIntent = new Intent(context, WidgetTimetable.class);
|
||||
refreshIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
|
||||
refreshIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
|
||||
PendingIntent pendingRefreshIntent = PendingIntent.getBroadcast(context,
|
||||
0, refreshIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
views.setOnClickPendingIntent(R.id.widgetTimetableRefresh, pendingRefreshIntent);
|
||||
|
||||
views.setOnClickPendingIntent(R.id.widgetTimetableSync, WidgetTimetable.getPendingSelfIntent(context, ACTION_SYNC_DATA));
|
||||
|
||||
views.setImageViewBitmap(R.id.widgetTimetableRefresh, new IconicsDrawable(context, CommunityMaterial.Icon2.cmd_refresh)
|
||||
.color(IconicsColor.colorInt(Color.WHITE))
|
||||
.size(IconicsSize.dp(widgetConfig.bigStyle ? 24 : 16)).toBitmap());
|
||||
|
||||
views.setImageViewBitmap(R.id.widgetTimetableSync, new IconicsDrawable(context, CommunityMaterial.Icon2.cmd_sync)
|
||||
.color(IconicsColor.colorInt(Color.WHITE))
|
||||
.size(IconicsSize.dp(widgetConfig.bigStyle ? 24 : 16)).toBitmap());
|
||||
|
||||
boolean unified = widgetConfig.profileId == -1;
|
||||
|
||||
List<Profile> profileList = new ArrayList<>();
|
||||
if (unified) {
|
||||
profileList = app.db.profileDao().getAllNow();
|
||||
filterOutArchived(profileList);
|
||||
}
|
||||
else {
|
||||
Profile profile = app.db.profileDao().getFullByIdNow(widgetConfig.profileId);
|
||||
if (profile != null) {
|
||||
profileList.add(profile);
|
||||
}
|
||||
}
|
||||
|
||||
//d(TAG, "Profiles: "+ Arrays.toString(profileList.toArray()));
|
||||
|
||||
if (profileList == null || profileList.size() == 0) {
|
||||
views.setViewVisibility(R.id.widgetTimetableLoading, View.VISIBLE);
|
||||
views.setTextViewText(R.id.widgetTimetableLoading, app.getString(R.string.widget_timetable_profile_doesnt_exist));
|
||||
}
|
||||
else {
|
||||
views.setViewVisibility(R.id.widgetTimetableLoading, View.GONE);
|
||||
//Register profile;
|
||||
|
||||
long bellSyncDiffMillis = 0;
|
||||
if (app.appConfig.bellSyncDiff != null) {
|
||||
bellSyncDiffMillis = app.appConfig.bellSyncDiff.hour * 60 * 60 * 1000 + app.appConfig.bellSyncDiff.minute * 60 * 1000 + app.appConfig.bellSyncDiff.second * 1000;
|
||||
bellSyncDiffMillis *= app.appConfig.bellSyncMultiplier;
|
||||
bellSyncDiffMillis *= -1;
|
||||
}
|
||||
|
||||
List<ItemWidgetTimetableModel> lessonList = new ArrayList<>();
|
||||
|
||||
Time syncedNow = Time.fromMillis(Time.getNow().getInMillis() + bellSyncDiffMillis);
|
||||
|
||||
Date today = Date.getToday();
|
||||
|
||||
int openProfileId = -1;
|
||||
Date displayingDate = null;
|
||||
int displayingWeekDay = 0;
|
||||
if (unified) {
|
||||
views.setTextViewText(R.id.widgetTimetableSubtitle, app.getString(R.string.widget_timetable_title_unified));
|
||||
}
|
||||
else {
|
||||
views.setTextViewText(R.id.widgetTimetableSubtitle, profileList.get(0).getName());
|
||||
openProfileId = profileList.get(0).getId();
|
||||
}
|
||||
|
||||
List<LessonFull> lessons = app.db.lessonDao().getAllWeekNow(unified ? -1 : openProfileId, today.clone().stepForward(0, 0, -today.getWeekDay()), today);
|
||||
|
||||
int scrollPos = 0;
|
||||
|
||||
for (Profile profile: profileList) {
|
||||
Date profileDisplayingDate = HomeFragment.findDateWithLessons(profile.getId(), lessons, syncedNow, 1);
|
||||
int profileDisplayingWeekDay = profileDisplayingDate.getWeekDay();
|
||||
int dayDiff = Date.diffDays(profileDisplayingDate, Date.getToday());
|
||||
|
||||
//d(TAG, "For profile "+profile.name+" displayingDate is "+profileDisplayingDate.getStringY_m_d());
|
||||
if (displayingDate == null || profileDisplayingDate.getValue() < displayingDate.getValue()) {
|
||||
displayingDate = profileDisplayingDate;
|
||||
displayingWeekDay = profileDisplayingWeekDay;
|
||||
//d(TAG, "Setting as global dd");
|
||||
if (dayDiff == 0) {
|
||||
views.setTextViewText(R.id.widgetTimetableTitle, app.getString(R.string.day_today_format, Week.getFullDayName(displayingWeekDay)));
|
||||
} else if (dayDiff == 1) {
|
||||
views.setTextViewText(R.id.widgetTimetableTitle, app.getString(R.string.day_tomorrow_format, Week.getFullDayName(displayingWeekDay)));
|
||||
} else {
|
||||
views.setTextViewText(R.id.widgetTimetableTitle, Week.getFullDayName(displayingWeekDay) + " " + profileDisplayingDate.getStringDm());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Profile profile: profileList) {
|
||||
int pos = 0;
|
||||
|
||||
List<EventFull> events = app.db.eventDao().getAllByDateNow(profile.getId(), displayingDate);
|
||||
if (events == null)
|
||||
events = new ArrayList<>();
|
||||
|
||||
if (unified) {
|
||||
ItemWidgetTimetableModel separator = new ItemWidgetTimetableModel();
|
||||
separator.profileId = profile.getId();
|
||||
separator.bigStyle = widgetConfig.bigStyle;
|
||||
separator.darkTheme = widgetConfig.darkTheme;
|
||||
separator.separatorProfileName = profile.getName();
|
||||
lessonList.add(separator);
|
||||
}
|
||||
|
||||
for (LessonFull lesson : lessons) {
|
||||
//d(TAG, "Profile "+profile.id+" Lesson profileId "+lesson.profileId+" weekDay "+lesson.weekDay+", "+lesson);
|
||||
if (profile.getId() != lesson.profileId || displayingWeekDay != lesson.weekDay)
|
||||
continue;
|
||||
//d(TAG, "Not skipped");
|
||||
ItemWidgetTimetableModel model = new ItemWidgetTimetableModel();
|
||||
|
||||
model.bigStyle = widgetConfig.bigStyle;
|
||||
model.darkTheme = widgetConfig.darkTheme;
|
||||
|
||||
model.profileId = profile.getId();
|
||||
|
||||
model.lessonDate = displayingDate;
|
||||
model.startTime = lesson.startTime;
|
||||
model.endTime = lesson.endTime;
|
||||
|
||||
model.lessonPassed = (syncedNow.getValue() > lesson.endTime.getValue()) && displayingWeekDay == Week.getTodayWeekDay();
|
||||
model.lessonCurrent = (Time.inRange(lesson.startTime, lesson.endTime, syncedNow)) && displayingWeekDay == Week.getTodayWeekDay();
|
||||
|
||||
if (model.lessonCurrent) {
|
||||
scrollPos = pos;
|
||||
} else if (model.lessonPassed) {
|
||||
scrollPos = pos + 1;
|
||||
}
|
||||
pos++;
|
||||
|
||||
model.subjectName = bs(lesson.subjectLongName);
|
||||
model.classroomName = lesson.classroomName;
|
||||
|
||||
model.bellSyncDiffMillis = bellSyncDiffMillis;
|
||||
|
||||
if (lesson.changeId != 0) {
|
||||
if (lesson.changeType == LessonChange.TYPE_CHANGE) {
|
||||
model.lessonChange = true;
|
||||
if (lesson.changedClassroomName()) {
|
||||
model.newClassroomName = lesson.changeClassroomName;
|
||||
}
|
||||
|
||||
if (lesson.changedSubjectLongName()) {
|
||||
model.newSubjectName = lesson.changeSubjectLongName;
|
||||
}
|
||||
}
|
||||
if (lesson.changeType == LessonChange.TYPE_CANCELLED) {
|
||||
model.lessonCancelled = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (EventFull event : events) {
|
||||
if (event.startTime == null)
|
||||
continue;
|
||||
if (event.eventDate.getValue() == displayingDate.getValue()
|
||||
&& event.startTime.getValue() == lesson.startTime.getValue()) {
|
||||
model.eventColors.add(event.type == TYPE_HOMEWORK ? ItemWidgetTimetableModel.EVENT_COLOR_HOMEWORK : event.getColor());
|
||||
}
|
||||
}
|
||||
|
||||
lessonList.add(model);
|
||||
}
|
||||
}
|
||||
|
||||
if (lessonList.size() == 0) {
|
||||
views.setViewVisibility(R.id.widgetTimetableLoading, View.VISIBLE);
|
||||
views.setRemoteAdapter(R.id.widgetTimetableListView, new Intent());
|
||||
views.setTextViewText(R.id.widgetTimetableLoading, app.getString(R.string.widget_timetable_no_lessons));
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views);
|
||||
}
|
||||
else {
|
||||
views.setViewVisibility(R.id.widgetTimetableLoading, View.GONE);
|
||||
|
||||
timetables.put(appWidgetId, lessonList);
|
||||
//WidgetTimetableListProvider.widgetsLessons.put(appWidgetId, lessons);
|
||||
//views.setRemoteAdapter(R.id.widgetTimetableListView, new Intent());
|
||||
Intent listIntent = new Intent(context, WidgetTimetableService.class);
|
||||
listIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
|
||||
listIntent.setData(Uri.parse(listIntent.toUri(Intent.URI_INTENT_SCHEME)));
|
||||
views.setRemoteAdapter(R.id.widgetTimetableListView, listIntent);
|
||||
|
||||
// template to handle the click listener for each item
|
||||
Intent intentTemplate = new Intent(context, LessonDetailsActivity.class);
|
||||
// Old activities shouldn't be in the history stack
|
||||
intentTemplate.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
PendingIntent pendingIntentTimetable = PendingIntent.getActivity(context,
|
||||
0,
|
||||
intentTemplate,
|
||||
0);
|
||||
views.setPendingIntentTemplate(R.id.widgetTimetableListView, pendingIntentTimetable);
|
||||
|
||||
Intent openIntent = new Intent(context, MainActivity.class);
|
||||
openIntent.setAction("android.intent.action.MAIN");
|
||||
if (!unified) {
|
||||
openIntent.putExtra("profileId", openProfileId);
|
||||
openIntent.putExtra("timetableDate", displayingDate.getValue());
|
||||
}
|
||||
openIntent.putExtra("fragmentId", MainActivity.DRAWER_ITEM_TIMETABLE);
|
||||
PendingIntent pendingOpenIntent = PendingIntent.getActivity(context,
|
||||
appWidgetId, openIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
views.setOnClickPendingIntent(R.id.widgetTimetableHeader, pendingOpenIntent);
|
||||
|
||||
if (!unified)
|
||||
views.setScrollPosition(R.id.widgetTimetableListView, scrollPos);
|
||||
}
|
||||
}
|
||||
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views);
|
||||
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widgetTimetableListView);
|
||||
}
|
||||
//modeInt++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnabled(Context context) {
|
||||
// Enter relevant functionality for when the first widget is created
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleted(Context context, int[] appWidgetIds) {
|
||||
App app = (App) context.getApplicationContext();
|
||||
for (int appWidgetId: appWidgetIds) {
|
||||
app.appConfig.widgetTimetableConfigs.remove(appWidgetId);
|
||||
}
|
||||
app.saveConfig("widgetTimetableConfigs");
|
||||
}
|
||||
}
|
||||
|
371
app/src/main/java/pl/szczodrzynski/edziennik/WidgetTimetable.kt
Normal file
371
app/src/main/java/pl/szczodrzynski/edziennik/WidgetTimetable.kt
Normal file
@ -0,0 +1,371 @@
|
||||
package pl.szczodrzynski.edziennik
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.appwidget.AppWidgetManager
|
||||
import android.appwidget.AppWidgetProvider
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.util.SparseArray
|
||||
import android.view.View
|
||||
import android.widget.RemoteViews
|
||||
import com.mikepenz.iconics.IconicsDrawable
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import com.mikepenz.iconics.utils.colorInt
|
||||
import com.mikepenz.iconics.utils.sizeDp
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.task.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event.TYPE_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.ItemWidgetTimetableModel
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||
import pl.szczodrzynski.edziennik.widgets.WidgetConfig
|
||||
import pl.szczodrzynski.edziennik.widgets.timetable.LessonDialogActivity
|
||||
import pl.szczodrzynski.edziennik.widgets.timetable.WidgetTimetableService
|
||||
import java.lang.reflect.InvocationTargetException
|
||||
|
||||
|
||||
class WidgetTimetable : AppWidgetProvider() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (ACTION_SYNC_DATA == intent.action) {
|
||||
EdziennikTask.sync().enqueue(context)
|
||||
}
|
||||
super.onReceive(context, intent)
|
||||
}
|
||||
|
||||
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
|
||||
val thisWidget = ComponentName(context, WidgetTimetable::class.java)
|
||||
|
||||
timetables = SparseArray()
|
||||
//timetables.clear();
|
||||
|
||||
val app = context.applicationContext as App
|
||||
|
||||
var bellSyncDiffMillis: Long = 0
|
||||
if (app.appConfig.bellSyncDiff != null) {
|
||||
bellSyncDiffMillis = (app.appConfig.bellSyncDiff.hour * 60 * 60 * 1000 + app.appConfig.bellSyncDiff.minute * 60 * 1000 + app.appConfig.bellSyncDiff.second * 1000).toLong()
|
||||
bellSyncDiffMillis *= app.appConfig.bellSyncMultiplier.toLong()
|
||||
bellSyncDiffMillis *= -1
|
||||
}
|
||||
|
||||
val allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget)
|
||||
|
||||
allWidgetIds?.forEach { appWidgetId ->
|
||||
var widgetConfig = app.appConfig.widgetTimetableConfigs[appWidgetId]
|
||||
if (widgetConfig == null) {
|
||||
widgetConfig = WidgetConfig(app.profileFirstId())
|
||||
app.appConfig.widgetTimetableConfigs[appWidgetId] = widgetConfig
|
||||
app.appConfig.savePending = true
|
||||
}
|
||||
|
||||
val views = if (widgetConfig.bigStyle) {
|
||||
RemoteViews(context.packageName, if (widgetConfig.darkTheme) R.layout.widget_timetable_dark_big else R.layout.widget_timetable_big)
|
||||
} else {
|
||||
RemoteViews(context.packageName, if (widgetConfig.darkTheme) R.layout.widget_timetable_dark else R.layout.widget_timetable)
|
||||
}
|
||||
|
||||
val refreshIntent = Intent(app, WidgetTimetable::class.java)
|
||||
refreshIntent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
|
||||
refreshIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds)
|
||||
val pendingRefreshIntent = PendingIntent.getBroadcast(context,
|
||||
0, refreshIntent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
views.setOnClickPendingIntent(R.id.widgetTimetableRefresh, pendingRefreshIntent)
|
||||
|
||||
views.setOnClickPendingIntent(R.id.widgetTimetableSync, getPendingSelfIntent(context, ACTION_SYNC_DATA))
|
||||
|
||||
views.setImageViewBitmap(R.id.widgetTimetableRefresh, IconicsDrawable(context, CommunityMaterial.Icon2.cmd_refresh)
|
||||
.colorInt(Color.WHITE)
|
||||
.sizeDp(if (widgetConfig.bigStyle) 24 else 16).toBitmap())
|
||||
|
||||
views.setImageViewBitmap(R.id.widgetTimetableSync, IconicsDrawable(context, CommunityMaterial.Icon2.cmd_sync)
|
||||
.colorInt(Color.WHITE)
|
||||
.sizeDp(if (widgetConfig.bigStyle) 24 else 16).toBitmap())
|
||||
|
||||
prepareAppWidget(app, appWidgetId, views, widgetConfig, bellSyncDiffMillis)
|
||||
|
||||
appWidgetManager.updateAppWidget(appWidgetId, views)
|
||||
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widgetTimetableListView)
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepareAppWidget(
|
||||
app: App,
|
||||
appWidgetId: Int,
|
||||
views: RemoteViews,
|
||||
widgetConfig: WidgetConfig,
|
||||
bellSyncDiffMillis: Long
|
||||
) {
|
||||
// get the current bell-synced time
|
||||
val now = Time.fromMillis(Time.getNow().inMillis + bellSyncDiffMillis)
|
||||
|
||||
// set the widget transparency
|
||||
val mode = PorterDuff.Mode.DST_IN
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
|
||||
// this code seems to crash the launcher on >= P
|
||||
val transparency = widgetConfig.opacity //0...1
|
||||
val colorFilter = 0x01000000L * (255f * transparency).toLong()
|
||||
try {
|
||||
val declaredMethods = Class.forName("android.widget.RemoteViews").declaredMethods
|
||||
val len = declaredMethods.size
|
||||
if (len > 0) {
|
||||
for (m in 0 until len) {
|
||||
val method = declaredMethods[m]
|
||||
if (method.name == "setDrawableParameters") {
|
||||
method.isAccessible = true
|
||||
method.invoke(views, R.id.widgetTimetableListView, true, -1, colorFilter.toInt(), mode, -1)
|
||||
method.invoke(views, R.id.widgetTimetableHeader, true, -1, colorFilter.toInt(), mode, -1)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: ClassNotFoundException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: InvocationTargetException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalAccessException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: IllegalArgumentException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
val unified = widgetConfig.profileId == -1
|
||||
|
||||
// get all profiles or one profile with the specified id
|
||||
val profileList = if (unified)
|
||||
app.db.profileDao().allNow.filterOutArchived()
|
||||
else
|
||||
listOfNotNull(app.db.profileDao().getByIdNow(widgetConfig.profileId))
|
||||
|
||||
// no profile was found
|
||||
if (profileList.isEmpty()) {
|
||||
views.setViewVisibility(R.id.widgetTimetableLoading, View.VISIBLE)
|
||||
views.setTextViewText(R.id.widgetTimetableLoading, app.getString(R.string.widget_timetable_profile_doesnt_exist))
|
||||
return
|
||||
}
|
||||
|
||||
views.setViewVisibility(R.id.widgetTimetableLoading, View.GONE)
|
||||
|
||||
// set lesson search bounds
|
||||
val today = Date.getToday()
|
||||
val searchEnd = today.clone().stepForward(0, 0, 7)
|
||||
|
||||
var scrollPos = 0
|
||||
|
||||
var profileId: Int? = null
|
||||
var displayingDate: Date? = null
|
||||
|
||||
val models = mutableListOf<ItemWidgetTimetableModel>()
|
||||
|
||||
// get all lessons within the search bounds
|
||||
val lessonList = app.db.timetableDao().getBetweenDatesNow(today, searchEnd)
|
||||
|
||||
for (profile in profileList) {
|
||||
|
||||
// add a profile separator with its name
|
||||
if (unified) {
|
||||
val separator = ItemWidgetTimetableModel()
|
||||
separator.profileId = profile.id
|
||||
separator.bigStyle = widgetConfig.bigStyle
|
||||
separator.darkTheme = widgetConfig.darkTheme
|
||||
separator.separatorProfileName = profile.name
|
||||
models.add(separator)
|
||||
}
|
||||
|
||||
// search for lessons to display
|
||||
val timetableDate = Date.getToday()
|
||||
var checkedDays = 0
|
||||
var lessons = lessonList.filter { it.profileId == profile.id && it.displayDate == timetableDate && it.type != Lesson.TYPE_NO_LESSONS }
|
||||
while ((lessons.isEmpty() || lessons.none {
|
||||
it.displayDate != today || (it.displayDate == today && it.displayEndTime != null && it.displayEndTime!! >= now)
|
||||
}) && checkedDays < 7) {
|
||||
timetableDate.stepForward(0, 0, 1)
|
||||
lessons = lessonList.filter { it.profileId == profile.id && it.displayDate == timetableDate && it.type != Lesson.TYPE_NO_LESSONS }
|
||||
checkedDays++
|
||||
}
|
||||
|
||||
// set the displayingDate to show in the header
|
||||
if (!unified) {
|
||||
if (lessons.isNotEmpty())
|
||||
displayingDate = timetableDate
|
||||
profileId = profile.id
|
||||
}
|
||||
|
||||
// get all events for the current date
|
||||
val events = app.db.eventDao().getAllByDateNow(profile.id, timetableDate)?.filterNotNull() ?: emptyList()
|
||||
|
||||
lessons.forEachIndexed { pos, lesson ->
|
||||
val model = ItemWidgetTimetableModel()
|
||||
|
||||
model.bigStyle = widgetConfig.bigStyle
|
||||
model.darkTheme = widgetConfig.darkTheme
|
||||
|
||||
model.profileId = profile.id
|
||||
|
||||
model.lessonId = lesson.id
|
||||
model.lessonDate = timetableDate
|
||||
model.startTime = lesson.startTime
|
||||
model.endTime = lesson.endTime
|
||||
|
||||
// check if the lesson has already passed or it's currently in progress
|
||||
if (lesson.displayDate == today) {
|
||||
lesson.displayEndTime?.let { endTime ->
|
||||
model.lessonPassed = now > endTime
|
||||
lesson.displayStartTime?.let { startTime ->
|
||||
model.lessonCurrent = now in startTime..endTime
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set where should the list view scroll to
|
||||
if (model.lessonCurrent) {
|
||||
scrollPos = pos
|
||||
} else if (model.lessonPassed) {
|
||||
scrollPos = pos + 1
|
||||
}
|
||||
|
||||
// set the subject and classroom name
|
||||
model.subjectName = lesson.displaySubjectName
|
||||
model.classroomName = lesson.displayClassroom
|
||||
|
||||
// set the bell sync to calculate progress in ListProvider
|
||||
model.bellSyncDiffMillis = bellSyncDiffMillis
|
||||
|
||||
// make the model aware of the lesson type
|
||||
when (lesson.type) {
|
||||
Lesson.TYPE_CANCELLED -> {
|
||||
model.lessonCancelled = true
|
||||
}
|
||||
Lesson.TYPE_CHANGE,
|
||||
Lesson.TYPE_SHIFTED_SOURCE,
|
||||
Lesson.TYPE_SHIFTED_TARGET -> {
|
||||
model.lessonChange = true
|
||||
}
|
||||
}
|
||||
|
||||
// add every event on this lesson
|
||||
for (event in events) {
|
||||
if (event.startTime != null && event.startTime != lesson.displayStartTime)
|
||||
continue
|
||||
model.eventColors.add(if (event.type == TYPE_HOMEWORK) ItemWidgetTimetableModel.EVENT_COLOR_HOMEWORK else event.getColor())
|
||||
}
|
||||
|
||||
models += model
|
||||
}
|
||||
}
|
||||
|
||||
if (unified) {
|
||||
// set the title for an unified widget
|
||||
views.setTextViewText(R.id.widgetTimetableTitle, app.getString(R.string.widget_timetable_title_unified))
|
||||
views.setViewVisibility(R.id.widgetTimetableSubtitle, View.GONE)
|
||||
} else {
|
||||
// set the title to present the widget's profile
|
||||
views.setTextViewText(R.id.widgetTimetableTitle, profileList[0].name)
|
||||
views.setViewVisibility(R.id.widgetTimetableTitle, View.VISIBLE)
|
||||
// make the subtitle show current date for these lessons
|
||||
displayingDate?.let {
|
||||
when (Date.diffDays(it, Date.getToday())) {
|
||||
0 -> views.setTextViewText(R.id.widgetTimetableSubtitle, app.getString(R.string.day_today_format, Week.getFullDayName(it.weekDay)))
|
||||
1 -> views.setTextViewText(R.id.widgetTimetableSubtitle, app.getString(R.string.day_tomorrow_format, Week.getFullDayName(it.weekDay)))
|
||||
else -> views.setTextViewText(R.id.widgetTimetableSubtitle, Week.getFullDayName(it.weekDay) + " " + it.formattedString)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// intent running when the header is clicked
|
||||
val openIntent = Intent(app, MainActivity::class.java)
|
||||
openIntent.action = "android.intent.action.MAIN"
|
||||
if (!unified) {
|
||||
// per-profile widget should redirect to it + correct day
|
||||
profileId?.let {
|
||||
openIntent.putExtra("profileId", it)
|
||||
}
|
||||
displayingDate?.let {
|
||||
openIntent.putExtra("timetableDate", it.value)
|
||||
}
|
||||
}
|
||||
openIntent.putExtra("fragmentId", MainActivity.DRAWER_ITEM_TIMETABLE)
|
||||
val pendingOpenIntent = PendingIntent.getActivity(app, appWidgetId, openIntent, 0)
|
||||
views.setOnClickPendingIntent(R.id.widgetTimetableHeader, pendingOpenIntent)
|
||||
|
||||
if (lessonList.isEmpty()) {
|
||||
views.setViewVisibility(R.id.widgetTimetableLoading, View.VISIBLE)
|
||||
views.setRemoteAdapter(R.id.widgetTimetableListView, Intent())
|
||||
views.setTextViewText(R.id.widgetTimetableLoading, app.getString(R.string.widget_timetable_no_lessons))
|
||||
return
|
||||
}
|
||||
|
||||
timetables!!.put(appWidgetId, models)
|
||||
|
||||
// apply the list service to the list view
|
||||
val listIntent = Intent(app, WidgetTimetableService::class.java)
|
||||
listIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
|
||||
listIntent.data = Uri.parse(listIntent.toUri(Intent.URI_INTENT_SCHEME))
|
||||
views.setRemoteAdapter(R.id.widgetTimetableListView, listIntent)
|
||||
|
||||
// create an intent used to display the lesson details dialog
|
||||
val intentTemplate = Intent(app, LessonDialogActivity::class.java)
|
||||
intentTemplate.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||
val pendingIntentTimetable = PendingIntent.getActivity(app, appWidgetId, intentTemplate, 0)
|
||||
views.setPendingIntentTemplate(R.id.widgetTimetableListView, pendingIntentTimetable)
|
||||
|
||||
if (!unified)
|
||||
views.setScrollPosition(R.id.widgetTimetableListView, scrollPos)
|
||||
}
|
||||
|
||||
override fun onEnabled(context: Context) {
|
||||
// Enter relevant functionality for when the first widget is created
|
||||
}
|
||||
|
||||
override fun onDeleted(context: Context, appWidgetIds: IntArray) {
|
||||
val app = context.applicationContext as App
|
||||
for (appWidgetId in appWidgetIds) {
|
||||
app.appConfig.widgetTimetableConfigs.remove(appWidgetId)
|
||||
}
|
||||
app.saveConfig("widgetTimetableConfigs")
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
|
||||
val ACTION_SYNC_DATA = "ACTION_SYNC_DATA"
|
||||
private val TAG = "WidgetTimetable"
|
||||
private val modeInt = 0
|
||||
|
||||
var timetables: SparseArray<List<ItemWidgetTimetableModel>>? = null
|
||||
|
||||
fun getPendingSelfIntent(context: Context, action: String): PendingIntent {
|
||||
val intent = Intent(context, WidgetTimetable::class.java)
|
||||
intent.action = action
|
||||
return getPendingSelfIntent(context, intent)
|
||||
}
|
||||
|
||||
fun getPendingSelfIntent(context: Context, intent: Intent): PendingIntent {
|
||||
return PendingIntent.getBroadcast(context, 0, intent, 0)
|
||||
}
|
||||
|
||||
fun drawableToBitmap(drawable: Drawable): Bitmap {
|
||||
|
||||
if (drawable is BitmapDrawable) {
|
||||
return drawable.bitmap
|
||||
}
|
||||
|
||||
val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
|
||||
val canvas = Canvas(bitmap)
|
||||
drawable.setBounds(0, 0, canvas.width, canvas.height)
|
||||
drawable.draw(canvas)
|
||||
|
||||
return bitmap
|
||||
}
|
||||
}
|
||||
}
|
@ -109,7 +109,7 @@ const val ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_ADDRESS = 206
|
||||
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_OTHER = 210
|
||||
const val ERROR_MOBIDZIENNIK_WEB_ACCESS_DENIED = 211
|
||||
const val ERROR_MOBIDZIENNIK_WEB_NO_SESSION_KEY = 212
|
||||
const val ERROR_MOBIDZIENNIK_WEB_NO_SESSION_VALUE = 212
|
||||
const val ERROR_MOBIDZIENNIK_WEB_NO_SESSION_VALUE = 216
|
||||
const val ERROR_MOBIDZIENNIK_WEB_NO_SERVER_ID = 213
|
||||
const val ERROR_MOBIDZIENNIK_WEB_INVALID_RESPONSE = 214
|
||||
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_NO_SESSION_ID = 215
|
||||
@ -163,3 +163,5 @@ const val EXCEPTION_LIBRUS_MESSAGES_REQUEST = 911
|
||||
const val EXCEPTION_IDZIENNIK_WEB_REQUEST = 912
|
||||
const val EXCEPTION_IDZIENNIK_WEB_API_REQUEST = 913
|
||||
const val EXCEPTION_IDZIENNIK_API_REQUEST = 914
|
||||
|
||||
const val LOGIN_NO_ARGUMENTS = 1201
|
||||
|
@ -7,39 +7,36 @@ package pl.szczodrzynski.edziennik.api.v2
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ANNOUNCEMENTS
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ATTENDANCE
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_GRADES
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOME
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
|
||||
|
||||
const val FEATURE_ALL = 0
|
||||
const val FEATURE_TIMETABLE = 1
|
||||
const val FEATURE_AGENDA = 2
|
||||
const val FEATURE_GRADES = 3
|
||||
const val FEATURE_HOMEWORK = 4
|
||||
const val FEATURE_BEHAVIOUR = 5
|
||||
const val FEATURE_ATTENDANCE = 6
|
||||
const val FEATURE_MESSAGES_INBOX = 7
|
||||
const val FEATURE_MESSAGES_SENT = 8
|
||||
const val FEATURE_ANNOUNCEMENTS = 9
|
||||
internal const val FEATURE_TIMETABLE = 1
|
||||
internal const val FEATURE_AGENDA = 2
|
||||
internal const val FEATURE_GRADES = 3
|
||||
internal const val FEATURE_HOMEWORK = 4
|
||||
internal const val FEATURE_BEHAVIOUR = 5
|
||||
internal const val FEATURE_ATTENDANCE = 6
|
||||
internal const val FEATURE_MESSAGES_INBOX = 7
|
||||
internal const val FEATURE_MESSAGES_SENT = 8
|
||||
internal const val FEATURE_ANNOUNCEMENTS = 9
|
||||
|
||||
const val FEATURE_ALWAYS_NEEDED = 100
|
||||
const val FEATURE_STUDENT_INFO = 101
|
||||
const val FEATURE_STUDENT_NUMBER = 109
|
||||
const val FEATURE_SCHOOL_INFO = 102
|
||||
const val FEATURE_CLASS_INFO = 103
|
||||
const val FEATURE_TEAM_INFO = 104
|
||||
const val FEATURE_LUCKY_NUMBER = 105
|
||||
const val FEATURE_TEACHERS = 106
|
||||
const val FEATURE_SUBJECTS = 107
|
||||
const val FEATURE_CLASSROOMS = 108
|
||||
const val FEATURE_PUSH_CONFIG = 120
|
||||
|
||||
const val FEATURE_MESSAGE_GET = 201
|
||||
internal const val FEATURE_ALWAYS_NEEDED = 100
|
||||
internal const val FEATURE_STUDENT_INFO = 101
|
||||
internal const val FEATURE_STUDENT_NUMBER = 109
|
||||
internal const val FEATURE_SCHOOL_INFO = 102
|
||||
internal const val FEATURE_CLASS_INFO = 103
|
||||
internal const val FEATURE_TEAM_INFO = 104
|
||||
internal const val FEATURE_LUCKY_NUMBER = 105
|
||||
internal const val FEATURE_TEACHERS = 106
|
||||
internal const val FEATURE_SUBJECTS = 107
|
||||
internal const val FEATURE_CLASSROOMS = 108
|
||||
internal const val FEATURE_PUSH_CONFIG = 120
|
||||
|
||||
object Features {
|
||||
private fun getAllNecessary(): List<Int> = listOf(
|
||||
|
@ -60,4 +60,8 @@ object Regexes {
|
||||
val IDZIENNIK_LOGIN_FIRST_STUDENT by lazy {
|
||||
"""<option.*?value="([0-9]+)"\sdata-id-ucznia="([A-z0-9]+?)".*?>(.+?)\s(.+?)\s*\((.+?),\s*(.+?)\)</option>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
}
|
||||
|
||||
val VULCAN_SHITFT_ANNOTATION by lazy {
|
||||
"""\(przeniesiona (z|na) lekcj[ię] ([0-9]+), (.+)\)""".toRegex()
|
||||
}
|
||||
}
|
||||
|
@ -44,16 +44,16 @@ class LibrusApiTimetables(override val data: DataLibrus,
|
||||
val lessonRange = lessonRangeEl?.asJsonArray?.asJsonObjectList()
|
||||
if (lessonRange?.isNullOrEmpty() == false)
|
||||
lessonsFound = true
|
||||
lessonRange?.forEachIndexed { index, lesson ->
|
||||
lessonRange?.forEach { lesson ->
|
||||
parseLesson(lessonDate, lesson)
|
||||
}
|
||||
}
|
||||
|
||||
if (day.isNullOrEmpty() || !lessonsFound) {
|
||||
data.lessonNewList += Lesson(profileId, lessonDate.value.toLong()).apply {
|
||||
data.lessonNewList.add(Lesson(profileId, lessonDate.value.toLong()).apply {
|
||||
type = Lesson.TYPE_NO_LESSONS
|
||||
date = lessonDate
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_MESSAGES_SENT
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusMessages
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
@ -20,7 +21,7 @@ import pl.szczodrzynski.edziennik.singleOrNull
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusMessagesGetList(override val data: DataLibrus, private val type: Int = Message.TYPE_RECEIVED,
|
||||
class LibrusMessagesGetList(override val data: DataLibrus, private val type: Int = TYPE_RECEIVED,
|
||||
archived: Boolean = false, val onSuccess: () -> Unit) : LibrusMessages(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusMessagesGetList"
|
||||
@ -28,7 +29,7 @@ class LibrusMessagesGetList(override val data: DataLibrus, private val type: Int
|
||||
|
||||
init {
|
||||
val endpoint = when (type) {
|
||||
Message.TYPE_RECEIVED -> "Inbox/action/GetList"
|
||||
TYPE_RECEIVED -> "Inbox/action/GetList"
|
||||
Message.TYPE_SENT -> "Outbox/action/GetList"
|
||||
else -> null
|
||||
}
|
||||
@ -46,34 +47,38 @@ class LibrusMessagesGetList(override val data: DataLibrus, private val type: Int
|
||||
else -> 0
|
||||
}
|
||||
val sentDate = Date.fromIso(element.select("sendDate").text().trim())
|
||||
var senderId: Long = -1
|
||||
var receiverId: Long = -1
|
||||
|
||||
when (type) {
|
||||
Message.TYPE_RECEIVED -> {
|
||||
val senderFirstName = element.select("senderFirstName").text().trim()
|
||||
val senderLastName = element.select("senderLastName").text().trim()
|
||||
senderId = data.teacherList.singleOrNull {
|
||||
it.name == senderFirstName && it.surname == senderLastName
|
||||
}?.id ?: -1
|
||||
}
|
||||
val recipientFirstName = element.select(when (type) {
|
||||
TYPE_RECEIVED -> "senderFirstName"
|
||||
else -> "receiverFirstName"
|
||||
}).text().trim()
|
||||
|
||||
Message.TYPE_SENT -> {
|
||||
val receiverFirstName = element.select("receiverFirstName").text().trim()
|
||||
val receiverLastName = element.select("receiverLastName").text().trim()
|
||||
receiverId = data.teacherList.singleOrNull {
|
||||
it.name == receiverFirstName && it.surname == receiverLastName
|
||||
}?.id ?: {
|
||||
val teacherObject = Teacher(
|
||||
profileId,
|
||||
-1 * Utils.crc16("$receiverFirstName $receiverLastName".toByteArray()).toLong(),
|
||||
receiverFirstName,
|
||||
receiverLastName
|
||||
)
|
||||
data.teacherList.put(teacherObject.id, teacherObject)
|
||||
teacherObject.id
|
||||
}.invoke()
|
||||
}
|
||||
val recipientLastName = element.select(when (type) {
|
||||
TYPE_RECEIVED -> "senderLastName"
|
||||
else -> "receiverLastName"
|
||||
}).text().trim()
|
||||
|
||||
val recipientId = data.teacherList.singleOrNull {
|
||||
it.name == recipientFirstName && it.surname == recipientLastName
|
||||
}?.id ?: {
|
||||
val teacherObject = Teacher(
|
||||
profileId,
|
||||
-1 * Utils.crc16("$recipientFirstName $recipientLastName".toByteArray()).toLong(),
|
||||
recipientFirstName,
|
||||
recipientLastName
|
||||
)
|
||||
data.teacherList.put(teacherObject.id, teacherObject)
|
||||
teacherObject.id
|
||||
}.invoke()
|
||||
|
||||
val senderId = when (type) {
|
||||
TYPE_RECEIVED -> recipientId
|
||||
else -> -1
|
||||
}
|
||||
|
||||
val receiverId = when (type) {
|
||||
TYPE_RECEIVED -> -1
|
||||
else -> recipientId
|
||||
}
|
||||
|
||||
val notified = when (type) {
|
||||
@ -112,7 +117,7 @@ class LibrusMessagesGetList(override val data: DataLibrus, private val type: Int
|
||||
}
|
||||
|
||||
when (type) {
|
||||
Message.TYPE_RECEIVED -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_RECEIVED, SYNC_ALWAYS)
|
||||
TYPE_RECEIVED -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_RECEIVED, SYNC_ALWAYS)
|
||||
Message.TYPE_SENT -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_SENT, DAY, DRAWER_ITEM_MESSAGES)
|
||||
}
|
||||
onSuccess()
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.App.profileId
|
||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
|
||||
import pl.szczodrzynski.edziennik.getById
|
||||
@ -25,7 +24,7 @@ class MobidziennikApiTeams(val data: DataMobidziennik, tableTeams: List<String>?
|
||||
val teacherId = cols[4].toLongOrNull() ?: -1
|
||||
|
||||
val teamObject = Team(
|
||||
profileId,
|
||||
data.profileId,
|
||||
id,
|
||||
name,
|
||||
type,
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.App.profileId
|
||||
import pl.szczodrzynski.edziennik.api.v2.mobidziennik.DataMobidziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
@ -93,7 +92,7 @@ class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
|
||||
|
||||
for (day in dataDays) {
|
||||
val lessonDate = Date.fromValue(day)
|
||||
data.lessonNewList += Lesson(profileId, lessonDate.value.toLong()).apply {
|
||||
data.lessonNewList += Lesson(data.profileId, lessonDate.value.toLong()).apply {
|
||||
type = Lesson.TYPE_NO_LESSONS
|
||||
date = lessonDate
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.models
|
||||
|
||||
import android.content.Context
|
||||
import com.google.gson.JsonObject
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
@ -52,6 +53,15 @@ class ApiError(val tag: String, val errorCode: Int) {
|
||||
)
|
||||
}
|
||||
|
||||
fun getStringReason(context: Context): String {
|
||||
return context.resources.getIdentifier("error_${errorCode}_reason", "string", context.packageName).let {
|
||||
if (it != 0)
|
||||
context.getString(it)
|
||||
else
|
||||
"?"
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "ApiError(tag='$tag', errorCode=$errorCode, profileId=$profileId, throwable=$throwable, apiResponse=$apiResponse, request=$request, response=$response, isCritical=$isCritical)"
|
||||
}
|
||||
|
@ -12,8 +12,10 @@ import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.api.v2.prepare
|
||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.VulcanData
|
||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.api.VulcanApiMessagesChangeStatus
|
||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.firstlogin.VulcanFirstLogin
|
||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.login.VulcanLogin
|
||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.login.VulcanLoginApi
|
||||
import pl.szczodrzynski.edziennik.api.v2.vulcanLoginMethods
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||
@ -63,7 +65,11 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
}
|
||||
|
||||
override fun getMessage(message: MessageFull) {
|
||||
|
||||
VulcanLoginApi(data) {
|
||||
VulcanApiMessagesChangeStatus(data, message) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun markAllAnnouncementsAsRead() {
|
||||
|
@ -64,6 +64,10 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
|
||||
VulcanApiAttendance(data, onSuccess)
|
||||
}
|
||||
ENDPOINT_VULCAN_API_TIMETABLE -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_timetable)
|
||||
VulcanApiTimetable(data, onSuccess)
|
||||
}
|
||||
ENDPOINT_VULCAN_API_MESSAGES_INBOX -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
||||
VulcanApiMessagesInbox(data, onSuccess)
|
||||
|
@ -55,7 +55,7 @@ class VulcanApiAttendance(override val data: DataVulcan, val onSuccess: () -> Un
|
||||
lessonSemester,
|
||||
attendance.getString("PrzedmiotNazwa") + attendanceCategory.name.let { " - $it" },
|
||||
lessonDate,
|
||||
data.lessonRanges.get(attendance.getInt("IdPoraLekcji") ?: 0)?.startTime,
|
||||
data.lessonRanges.get(attendance.getInt("Numer") ?: 0)?.startTime,
|
||||
type)
|
||||
|
||||
data.attendanceList.add(attendanceObject)
|
||||
|
@ -35,7 +35,7 @@ class VulcanApiDictionaries(override val data: DataVulcan, val onSuccess: () ->
|
||||
elements?.getJsonArray("KategorieUwag")?.forEach { saveNoticeType(it.asJsonObject) }
|
||||
elements?.getJsonArray("KategorieFrekwencji")?.forEach { saveAttendanceType(it.asJsonObject) }
|
||||
|
||||
data.setSyncNext(ENDPOINT_VULCAN_API_DICTIONARIES, 4*DAY)
|
||||
data.setSyncNext(ENDPOINT_VULCAN_API_DICTIONARIES, 4 * DAY)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
@ -73,7 +73,7 @@ class VulcanApiDictionaries(override val data: DataVulcan, val onSuccess: () ->
|
||||
}
|
||||
|
||||
private fun saveLessonRange(lessonRange: JsonObject) {
|
||||
val lessonNumber = lessonRange.getInt("Id") ?: return
|
||||
val lessonNumber = lessonRange.getInt("Numer") ?: return
|
||||
val startTime = lessonRange.getString("PoczatekTekst")?.let { Time.fromH_m(it) } ?: return
|
||||
val endTime = lessonRange.getString("KoniecTekst")?.let { Time.fromH_m(it) } ?: return
|
||||
|
||||
@ -126,8 +126,7 @@ class VulcanApiDictionaries(override val data: DataVulcan, val onSuccess: () ->
|
||||
Attendance.TYPE_ABSENT_EXCUSED
|
||||
else
|
||||
Attendance.TYPE_ABSENT
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val belated = attendanceType.getBoolean("Spoznienie") ?: false
|
||||
val released = attendanceType.getBoolean("Zwolnienie") ?: false
|
||||
val present = attendanceType.getBoolean("Obecnosc") ?: true
|
||||
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-11-12
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.vulcan.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_MESSAGES_CHANGE_STATUS
|
||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan
|
||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.VulcanApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
|
||||
class VulcanApiMessagesChangeStatus(
|
||||
override val data: DataVulcan,
|
||||
private val messageObject: MessageFull,
|
||||
val onSuccess: () -> Unit
|
||||
) : VulcanApi(data) {
|
||||
companion object {
|
||||
const val TAG = "VulcanApiMessagesChangeStatus"
|
||||
}
|
||||
|
||||
init {
|
||||
data.profile?.also { profile ->
|
||||
apiGet(TAG, VULCAN_API_ENDPOINT_MESSAGES_CHANGE_STATUS, parameters = mapOf(
|
||||
"WiadomoscId" to messageObject.id,
|
||||
"FolderWiadomosci" to "Odebrane",
|
||||
"Status" to "Widoczna",
|
||||
"LoginId" to data.studentLoginId,
|
||||
"IdUczen" to data.studentId
|
||||
)) { _, _ ->
|
||||
|
||||
if (!messageObject.seen) {
|
||||
data.messageMetadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_MESSAGE,
|
||||
messageObject.id,
|
||||
true,
|
||||
true,
|
||||
messageObject.addedDate
|
||||
))
|
||||
}
|
||||
|
||||
if (messageObject.type != TYPE_SENT) {
|
||||
val messageRecipientObject = MessageRecipient(
|
||||
profileId,
|
||||
-1,
|
||||
-1,
|
||||
System.currentTimeMillis(),
|
||||
messageObject.id
|
||||
)
|
||||
|
||||
data.messageRecipientList.add(messageRecipientObject)
|
||||
}
|
||||
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -14,6 +14,8 @@ import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class VulcanApiMessagesInbox(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
|
||||
@ -43,7 +45,22 @@ class VulcanApiMessagesInbox(override val data: DataVulcan, val onSuccess: () ->
|
||||
|
||||
val senderLoginId = message.getString("NadawcaId") ?: return@forEach
|
||||
val senderId = data.teacherList
|
||||
.singleOrNull { it.loginId == senderLoginId }?.id ?: return@forEach
|
||||
.singleOrNull { it.loginId == senderLoginId }?.id ?: {
|
||||
|
||||
val senderName = message.getString("Nadawca") ?: ""
|
||||
|
||||
senderName.getLastFirstName()?.let { (senderLastName, senderFirstName) ->
|
||||
val teacherObject = Teacher(
|
||||
profileId,
|
||||
-1 * Utils.crc16(senderName.toByteArray()).toLong(),
|
||||
senderFirstName,
|
||||
senderLastName,
|
||||
senderLoginId
|
||||
)
|
||||
data.teacherList.put(teacherObject.id, teacherObject)
|
||||
teacherObject.id
|
||||
}
|
||||
}.invoke() ?: -1
|
||||
|
||||
val sentDate = message.getLong("DataWyslaniaUnixEpoch")?.let { it * 1000 }
|
||||
?: -1
|
||||
|
@ -14,6 +14,8 @@ import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class VulcanApiMessagesSent(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
|
||||
@ -23,11 +25,11 @@ class VulcanApiMessagesSent(override val data: DataVulcan, val onSuccess: () ->
|
||||
|
||||
init {
|
||||
data.profile?.also { profile ->
|
||||
val startDate: String = when (profile.empty) {
|
||||
true -> profile.getSemesterStart(profile.currentSemester).stringY_m_d
|
||||
else -> Date.getToday().stepForward(0, -1, 0).stringY_m_d
|
||||
val startDate: Long = when (profile.empty) {
|
||||
true -> profile.getSemesterStart(profile.currentSemester).inUnix
|
||||
else -> Date.getToday().stepForward(0, -1, 0).inUnix
|
||||
}
|
||||
val endDate: String = profile.getSemesterEnd(profile.currentSemester).stringY_m_d
|
||||
val endDate: Long = profile.getSemesterEnd(profile.currentSemester).inUnix
|
||||
|
||||
apiGet(TAG, VULCAN_API_ENDPOINT_MESSAGES_SENT, parameters = mapOf(
|
||||
"DataPoczatkowa" to startDate,
|
||||
@ -43,23 +45,27 @@ class VulcanApiMessagesSent(override val data: DataVulcan, val onSuccess: () ->
|
||||
val unreadBy = message.getInt("Nieprzeczytane") ?: 0
|
||||
val sentDate = message.getLong("DataWyslaniaUnixEpoch")?.let { it * 1000 } ?: -1
|
||||
|
||||
val messageObject = Message(
|
||||
profileId,
|
||||
id,
|
||||
subject,
|
||||
body,
|
||||
TYPE_SENT,
|
||||
-1,
|
||||
-1
|
||||
)
|
||||
|
||||
message.getJsonArray("Adresaci")?.asJsonObjectList()
|
||||
?.forEachIndexed { _, recipient ->
|
||||
?.onEach { receiver ->
|
||||
|
||||
val recipientLoginId = recipient.getString("LoginId")
|
||||
?: return@forEachIndexed
|
||||
val recipientId = data.teacherList.singleOrNull { it.loginId == recipientLoginId }?.id
|
||||
?: return@forEachIndexed
|
||||
val receiverLoginId = receiver.getString("LoginId")
|
||||
?: return@onEach
|
||||
val receiverId = data.teacherList.singleOrNull { it.loginId == receiverLoginId }?.id
|
||||
?: {
|
||||
val receiverName = receiver.getString("Nazwa") ?: ""
|
||||
|
||||
receiverName.getLastFirstName()?.let { (receiverLastName, receiverFirstName) ->
|
||||
val teacherObject = Teacher(
|
||||
profileId,
|
||||
-1 * Utils.crc16(receiverName.toByteArray()).toLong(),
|
||||
receiverFirstName,
|
||||
receiverLastName,
|
||||
receiverLoginId
|
||||
)
|
||||
data.teacherList.put(teacherObject.id, teacherObject)
|
||||
teacherObject.id
|
||||
}
|
||||
}.invoke() ?: -1
|
||||
|
||||
val readDate: Long = when (readBy) {
|
||||
0 -> 0
|
||||
@ -71,7 +77,7 @@ class VulcanApiMessagesSent(override val data: DataVulcan, val onSuccess: () ->
|
||||
|
||||
val messageRecipientObject = MessageRecipient(
|
||||
profileId,
|
||||
recipientId,
|
||||
receiverId,
|
||||
-1,
|
||||
readDate,
|
||||
id
|
||||
@ -80,6 +86,16 @@ class VulcanApiMessagesSent(override val data: DataVulcan, val onSuccess: () ->
|
||||
data.messageRecipientList.add(messageRecipientObject)
|
||||
}
|
||||
|
||||
val messageObject = Message(
|
||||
profileId,
|
||||
id,
|
||||
subject,
|
||||
body,
|
||||
TYPE_SENT,
|
||||
-1,
|
||||
-1
|
||||
)
|
||||
|
||||
data.messageIgnoreList.add(messageObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
|
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-11-13
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.vulcan.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.Regexes
|
||||
import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_TIMETABLE
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan
|
||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.ENDPOINT_VULCAN_API_TIMETABLE
|
||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.data.VulcanApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.subjects.Subject
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.crc16
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class VulcanApiTimetable(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
|
||||
companion object {
|
||||
const val TAG = "VulcanApiTimetable"
|
||||
}
|
||||
|
||||
init {
|
||||
data.profile?.also { profile ->
|
||||
val currentWeekStart = Date.getToday().let { it.stepForward(0, 0, -it.weekDay) }
|
||||
val getDate = data.arguments?.getString("weekStart") ?: currentWeekStart.stringY_m_d
|
||||
|
||||
val weekStart = Date.fromY_m_d(getDate)
|
||||
val weekEnd = weekStart.clone().stepForward(0, 0, 6)
|
||||
|
||||
apiGet(TAG, VULCAN_API_ENDPOINT_TIMETABLE, parameters = mapOf(
|
||||
"DataPoczatkowa" to weekStart.stringY_m_d,
|
||||
"DataKoncowa" to weekEnd.stringY_m_d,
|
||||
"IdUczen" to data.studentId,
|
||||
"IdOddzial" to data.studentClassId,
|
||||
"IdOkresKlasyfikacyjny" to data.studentSemesterId
|
||||
)) { json, _ ->
|
||||
val dates: MutableSet<Int> = mutableSetOf()
|
||||
val lessons: MutableList<Lesson> = mutableListOf()
|
||||
|
||||
json.getJsonArray("Data")?.asJsonObjectList()?.forEach { lesson ->
|
||||
val lessonDate = Date.fromY_m_d(lesson.getString("DzienTekst"))
|
||||
val lessonNumber = lesson.getInt("NumerLekcji")
|
||||
val lessonRange = data.lessonRanges.singleOrNull { it.lessonNumber == lessonNumber }
|
||||
val startTime = lessonRange?.startTime
|
||||
val endTime = lessonRange?.endTime
|
||||
val teacherId = lesson.getLong("IdPracownik")
|
||||
val teamId = data.studentClassId.toLong()
|
||||
val classroom = lesson.getString("Classroom")
|
||||
|
||||
val oldTeacherId = lesson.getLong("IdPracownikOld")
|
||||
|
||||
val changeAnnotation = lesson.getString("AdnotacjaOZmianie") ?: ""
|
||||
val type = when {
|
||||
changeAnnotation.startsWith("(przeniesiona z") -> Lesson.TYPE_SHIFTED_TARGET
|
||||
changeAnnotation.startsWith("(przeniesiona na") -> Lesson.TYPE_SHIFTED_SOURCE
|
||||
changeAnnotation.startsWith("(zastępstwo") -> Lesson.TYPE_CHANGE
|
||||
lesson.getBoolean("PrzekreslonaNazwa") == true -> Lesson.TYPE_CANCELLED
|
||||
else -> Lesson.TYPE_NORMAL
|
||||
}
|
||||
|
||||
val subjectId = lesson.getLong("IdPrzedmiot")?.let {
|
||||
when (it) {
|
||||
0L -> {
|
||||
val subjectName = lesson.getString("PrzedmiotNazwa") ?: ""
|
||||
|
||||
data.subjectList.singleOrNull { subject -> subject.longName == subjectName }?.id
|
||||
?: {
|
||||
/**
|
||||
* CREATE A NEW SUBJECT IF IT DOESN'T EXIST
|
||||
*/
|
||||
|
||||
val subjectObject = Subject(
|
||||
profileId,
|
||||
-1 * crc16(subjectName.toByteArray()).toLong(),
|
||||
subjectName,
|
||||
subjectName
|
||||
)
|
||||
data.subjectList.put(subjectObject.id, subjectObject)
|
||||
subjectObject.id
|
||||
}.invoke()
|
||||
}
|
||||
else -> it
|
||||
}
|
||||
}
|
||||
|
||||
val id = lessonDate.combineWith(startTime) / 6L * 10L + (lesson.hashCode() and 0xFFFF)
|
||||
|
||||
val lessonObject = Lesson(profileId, id).apply {
|
||||
this.type = type
|
||||
|
||||
when (type) {
|
||||
Lesson.TYPE_NORMAL, Lesson.TYPE_CHANGE, Lesson.TYPE_SHIFTED_TARGET -> {
|
||||
this.date = lessonDate
|
||||
this.lessonNumber = lessonNumber
|
||||
this.startTime = startTime
|
||||
this.endTime = endTime
|
||||
this.subjectId = subjectId
|
||||
this.teacherId = teacherId
|
||||
this.teamId = teamId
|
||||
this.classroom = classroom
|
||||
|
||||
this.oldTeacherId = oldTeacherId
|
||||
}
|
||||
|
||||
Lesson.TYPE_CANCELLED, Lesson.TYPE_SHIFTED_SOURCE -> {
|
||||
this.oldDate = lessonDate
|
||||
this.oldLessonNumber = lessonNumber
|
||||
this.oldStartTime = startTime
|
||||
this.oldEndTime = endTime
|
||||
this.oldSubjectId = subjectId
|
||||
this.oldTeacherId = teacherId
|
||||
this.oldTeamId = teamId
|
||||
this.oldClassroom = classroom
|
||||
}
|
||||
}
|
||||
|
||||
if (type == Lesson.TYPE_SHIFTED_SOURCE || type == Lesson.TYPE_SHIFTED_TARGET) {
|
||||
val shift = Regexes.VULCAN_SHITFT_ANNOTATION.find(changeAnnotation)
|
||||
val oldLessonNumber = shift?.get(2)?.toInt()
|
||||
val oldLessonDate = shift?.get(3)?.let { Date.fromd_m_Y(it) }
|
||||
|
||||
val oldLessonRange = data.lessonRanges.singleOrNull { it.lessonNumber == oldLessonNumber }
|
||||
val oldStartTime = oldLessonRange?.startTime
|
||||
val oldEndTime = oldLessonRange?.endTime
|
||||
|
||||
when (type) {
|
||||
Lesson.TYPE_SHIFTED_SOURCE -> {
|
||||
this.lessonNumber = oldLessonNumber
|
||||
this.date = oldLessonDate
|
||||
this.startTime = oldStartTime
|
||||
this.endTime = oldEndTime
|
||||
}
|
||||
|
||||
Lesson.TYPE_SHIFTED_TARGET -> {
|
||||
this.oldLessonNumber = oldLessonNumber
|
||||
this.oldDate = oldLessonDate
|
||||
this.oldStartTime = oldStartTime
|
||||
this.oldEndTime = oldEndTime
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type != Lesson.TYPE_NORMAL) {
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_LESSON_CHANGE,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
|
||||
dates.add(lessonDate.value)
|
||||
lessons.add(lessonObject)
|
||||
}
|
||||
|
||||
val date: Date = weekStart.clone()
|
||||
while (date <= weekEnd) {
|
||||
if (!dates.contains(date.value)) {
|
||||
lessons.add(Lesson(profileId, date.value.toLong()).apply {
|
||||
this.type = Lesson.TYPE_NO_LESSONS
|
||||
this.date = date.clone()
|
||||
})
|
||||
}
|
||||
|
||||
date.stepForward(0, 0, 1)
|
||||
}
|
||||
|
||||
d(TAG, "Clearing lessons between ${weekStart.stringY_m_d} and ${weekEnd.stringY_m_d} - timetable downloaded for $getDate")
|
||||
|
||||
data.lessonNewList.addAll(lessons)
|
||||
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
||||
|
||||
data.setSyncNext(ENDPOINT_VULCAN_API_TIMETABLE, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,11 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
||||
|
||||
import im.wangchao.mhttp.Request;
|
||||
|
||||
/**
|
||||
* Callback containing a {@link Request.Builder} which has correct headers and body to download a corresponding message attachment when ran.
|
||||
* {@code onSuccess} has to be ran on the UI thread.
|
||||
*/
|
||||
public interface AttachmentGetCallback {
|
||||
void onSuccess(Request.Builder builder);
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull;
|
||||
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.teachers.Teacher;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesComposeInfo;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Endpoint;
|
||||
|
||||
public interface EdziennikInterface {
|
||||
|
||||
/**
|
||||
* Sync all Edziennik data.
|
||||
* Ran always on worker thread.
|
||||
*
|
||||
* @param activityContext a {@link Context}, used for resource extractions, passed back to {@link SyncCallback}
|
||||
* @param callback ran on worker thread.
|
||||
* @param profileId
|
||||
* @param profile
|
||||
* @param loginStore
|
||||
*/
|
||||
void sync(@NonNull Context activityContext, @NonNull SyncCallback callback, int profileId, @Nullable Profile profile, @NonNull LoginStore loginStore);
|
||||
void syncMessages(@NonNull Context activityContext, @NonNull SyncCallback errorCallback, @NonNull ProfileFull profile);
|
||||
void syncFeature(@NonNull Context activityContext, @NonNull SyncCallback callback, @NonNull ProfileFull profile, int ... featureList);
|
||||
|
||||
int FEATURE_ALL = 0;
|
||||
int FEATURE_TIMETABLE = 1;
|
||||
int FEATURE_AGENDA = 2;
|
||||
int FEATURE_GRADES = 3;
|
||||
int FEATURE_HOMEWORK = 4;
|
||||
int FEATURE_NOTICES = 5;
|
||||
int FEATURE_ATTENDANCE = 6;
|
||||
int FEATURE_MESSAGES_INBOX = 7;
|
||||
int FEATURE_MESSAGES_OUTBOX = 8;
|
||||
int FEATURE_ANNOUNCEMENTS = 9;
|
||||
|
||||
/**
|
||||
* Download a single message or get its recipient list if it's already downloaded.
|
||||
*
|
||||
* May be executed on any thread.
|
||||
*
|
||||
* @param activityContext
|
||||
* @param errorCallback used for error reporting. Ran on a background thread.
|
||||
* @param profile
|
||||
* @param message a message of which body and recipient list should be downloaded.
|
||||
* @param messageCallback always executed on UI thread.
|
||||
*/
|
||||
void getMessage(@NonNull Context activityContext, @NonNull SyncCallback errorCallback, @NonNull ProfileFull profile, @NonNull MessageFull message, @NonNull MessageGetCallback messageCallback);
|
||||
void getAttachment(@NonNull Context activityContext, @NonNull SyncCallback errorCallback, @NonNull ProfileFull profile, @NonNull MessageFull message, long attachmentId, @NonNull AttachmentGetCallback attachmentCallback);
|
||||
//void getMessageList(@NonNull Context activityContext, @NonNull SyncCallback errorCallback, @NonNull ProfileFull profile, int type, @NonNull MessageListCallback messageCallback);
|
||||
/**
|
||||
* Download a list of available message recipients.
|
||||
*
|
||||
* Updates a database-saved {@code teacherList} with {@code loginId}s.
|
||||
*
|
||||
* A {@link Teacher} is considered as a recipient when its {@code loginId} is not null.
|
||||
*
|
||||
* May be executed on any thread.
|
||||
*
|
||||
* @param activityContext
|
||||
* @param errorCallback used for error reporting. Ran on a background thread.
|
||||
* @param profile
|
||||
* @param recipientListGetCallback always executed on UI thread.
|
||||
*/
|
||||
void getRecipientList(@NonNull Context activityContext, @NonNull SyncCallback errorCallback, @NonNull ProfileFull profile, @NonNull RecipientListGetCallback recipientListGetCallback);
|
||||
MessagesComposeInfo getComposeInfo(@NonNull ProfileFull profile);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param profile a {@link Profile} containing already changed endpoints
|
||||
* @return a map of configurable {@link Endpoint}s along with their names, {@code null} when unsupported
|
||||
*/
|
||||
Map<String, Endpoint> getConfigurableEndpoints(Profile profile);
|
||||
|
||||
/**
|
||||
* Check if the specified endpoint is enabled for the current profile.
|
||||
*
|
||||
* @param profile a {@link Profile} containing already changed endpoints
|
||||
* @param defaultActive if the endpoint is enabled by default.
|
||||
* @param name the endpoint's name
|
||||
* @return {@code true} if the endpoint is enabled, {@code false} when it's not. Return {@code defaultActive} if unsupported.
|
||||
*/
|
||||
boolean isEndpointEnabled(Profile profile, boolean defaultActive, String name);
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.api.AppError;
|
||||
|
||||
public interface ErrorCallback {
|
||||
void onError(Context activityContext, @NonNull AppError error);
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
||||
|
||||
public interface LoginCallback {
|
||||
void onSuccess();
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull;
|
||||
|
||||
/**
|
||||
* Callback containing a {@link MessageFull} which already has its {@code body} and {@code recipients}.
|
||||
* {@code onSuccess} is always ran on the UI thread.
|
||||
*/
|
||||
public interface MessageGetCallback {
|
||||
void onSuccess(MessageFull message);
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull;
|
||||
|
||||
public interface MessageListCallback {
|
||||
void onSuccess(List<MessageFull> messageList);
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
|
||||
public interface ProgressCallback extends ErrorCallback {
|
||||
void onProgress(int progressStep);
|
||||
void onActionStarted(@StringRes int stringResId);
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher;
|
||||
|
||||
public interface RecipientListGetCallback {
|
||||
void onSuccess(List<Teacher> teacherList);
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.interfaces;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileFull;
|
||||
|
||||
/**
|
||||
* A callback used for error reporting, progress information.
|
||||
* All the methods are always ran on a worker thread.
|
||||
*/
|
||||
public interface SyncCallback extends ProgressCallback {
|
||||
void onLoginFirst(List<Profile> profileList, LoginStore loginStore);
|
||||
void onSuccess(Context activityContext, ProfileFull profileFull);
|
||||
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.v2
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.api.AppError
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
|
||||
data class ApiLoginResult(val loginStore: LoginStore, val error: AppError?)
|
@ -1,6 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.v2
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.api.AppError
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
|
||||
data class FirstLoginResult(val profileList: ArrayList<Profile>, val error: AppError?)
|
@ -1,12 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.v2.librus.firstlogin
|
||||
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.ProgressCallback
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
|
||||
class FirstLoginLibrus(val app: App, val loginStore: LoginStore, val progressCallback: ProgressCallback, val onSuccess: (profileList: List<Profile>) -> Unit) {
|
||||
init {
|
||||
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.v2.librus.firstlogin
|
||||
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.ProgressCallback
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
|
||||
class FirstLoginSynergia(val app: App, val loginStore: LoginStore, val progressCallback: ProgressCallback, val onSuccess: (profileList: List<Profile>) -> Unit) {
|
||||
init {
|
||||
|
||||
}
|
||||
}
|
@ -10,6 +10,27 @@ import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
@Dao
|
||||
interface TimetableDao {
|
||||
companion object {
|
||||
private const val QUERY = """
|
||||
SELECT
|
||||
timetable.*,
|
||||
subjects.subjectLongName AS subjectName,
|
||||
teachers.teacherName ||" "|| teachers.teacherSurname AS teacherName,
|
||||
teams.teamName AS teamName,
|
||||
oldS.subjectLongName AS oldSubjectName,
|
||||
oldT.teacherName ||" "|| oldT.teacherSurname AS oldTeacherName,
|
||||
oldG.teamName AS oldTeamName,
|
||||
metadata.seen, metadata.notified, metadata.addedDate
|
||||
FROM timetable
|
||||
LEFT JOIN subjects USING(profileId, subjectId)
|
||||
LEFT JOIN teachers USING(profileId, teacherId)
|
||||
LEFT JOIN teams USING(profileId, teamId)
|
||||
LEFT JOIN subjects AS oldS ON timetable.profileId = oldS.profileId AND timetable.oldSubjectId = oldS.subjectId
|
||||
LEFT JOIN teachers AS oldT ON timetable.profileId = oldT.profileId AND timetable.oldTeacherId = oldT.teacherId
|
||||
LEFT JOIN teams AS oldG ON timetable.profileId = oldG.profileId AND timetable.oldTeamId = oldG.teamId
|
||||
LEFT JOIN metadata ON id = thingId AND thingType = ${Metadata.TYPE_LESSON_CHANGE} AND metadata.profileId = timetable.profileId
|
||||
"""
|
||||
}
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
operator fun plusAssign(lessonList: List<Lesson>)
|
||||
@ -25,49 +46,31 @@ interface TimetableDao {
|
||||
fun clearBetweenDates(profileId: Int, dateFrom: Date, dateTo: Date)
|
||||
|
||||
@Query("""
|
||||
SELECT
|
||||
timetable.*,
|
||||
subjects.subjectLongName AS subjectName,
|
||||
teachers.teacherName ||" "|| teachers.teacherSurname AS teacherName,
|
||||
teams.teamName AS teamName,
|
||||
oldS.subjectLongName AS oldSubjectName,
|
||||
oldT.teacherName ||" "|| oldT.teacherSurname AS oldTeacherName,
|
||||
oldG.teamName AS oldTeamName,
|
||||
metadata.seen, metadata.notified, metadata.addedDate
|
||||
FROM timetable
|
||||
LEFT JOIN subjects USING(profileId, subjectId)
|
||||
LEFT JOIN teachers USING(profileId, teacherId)
|
||||
LEFT JOIN teams USING(profileId, teamId)
|
||||
LEFT JOIN subjects AS oldS ON timetable.profileId = oldS.profileId AND timetable.oldSubjectId = oldS.subjectId
|
||||
LEFT JOIN teachers AS oldT ON timetable.profileId = oldT.profileId AND timetable.oldTeacherId = oldT.teacherId
|
||||
LEFT JOIN teams AS oldG ON timetable.profileId = oldG.profileId AND timetable.oldTeamId = oldG.teamId
|
||||
LEFT JOIN metadata ON id = thingId AND thingType = ${Metadata.TYPE_LESSON_CHANGE} AND metadata.profileId = timetable.profileId
|
||||
$QUERY
|
||||
WHERE timetable.profileId = :profileId AND (type != 3 AND date = :date) OR ((type = 3 OR type = 1) AND oldDate = :date)
|
||||
ORDER BY id, type
|
||||
""")
|
||||
fun getForDate(profileId: Int, date: Date) : LiveData<List<LessonFull>>
|
||||
|
||||
@Query("""
|
||||
SELECT
|
||||
timetable.*,
|
||||
subjects.subjectLongName AS subjectName,
|
||||
teachers.teacherName ||" "|| teachers.teacherSurname AS teacherName,
|
||||
teams.teamName AS teamName,
|
||||
oldS.subjectLongName AS oldSubjectName,
|
||||
oldT.teacherName ||" "|| oldT.teacherSurname AS oldTeacherName,
|
||||
oldG.teamName AS oldTeamName,
|
||||
metadata.seen, metadata.notified, metadata.addedDate
|
||||
FROM timetable
|
||||
LEFT JOIN subjects USING(profileId, subjectId)
|
||||
LEFT JOIN teachers USING(profileId, teacherId)
|
||||
LEFT JOIN teams USING(profileId, teamId)
|
||||
LEFT JOIN subjects AS oldS ON timetable.profileId = oldS.profileId AND timetable.oldSubjectId = oldS.subjectId
|
||||
LEFT JOIN teachers AS oldT ON timetable.profileId = oldT.profileId AND timetable.oldTeacherId = oldT.teacherId
|
||||
LEFT JOIN teams AS oldG ON timetable.profileId = oldG.profileId AND timetable.oldTeamId = oldG.teamId
|
||||
LEFT JOIN metadata ON id = thingId AND thingType = ${Metadata.TYPE_LESSON_CHANGE} AND metadata.profileId = timetable.profileId
|
||||
$QUERY
|
||||
WHERE timetable.profileId = :profileId AND ((type != 3 AND date > :today) OR ((type = 3 OR type = 1) AND oldDate > :today)) AND timetable.subjectId = :subjectId
|
||||
ORDER BY id, type
|
||||
LIMIT 1
|
||||
""")
|
||||
fun getNextWithSubject(profileId: Int, today: Date, subjectId: Long) : LiveData<LessonFull>
|
||||
|
||||
@Query("""
|
||||
$QUERY
|
||||
WHERE (type != 3 AND date >= :dateFrom AND date <= :dateTo) OR ((type = 3 OR type = 1) AND oldDate >= :dateFrom AND oldDate <= :dateTo)
|
||||
ORDER BY profileId, id, type
|
||||
""")
|
||||
fun getBetweenDatesNow(dateFrom: Date, dateTo: Date) : List<LessonFull>
|
||||
|
||||
@Query("""
|
||||
$QUERY
|
||||
WHERE timetable.profileId = :profileId AND timetable.id = :lessonId
|
||||
ORDER BY id, type
|
||||
""")
|
||||
fun getByIdNow(profileId: Int, lessonId: Long) : LessonFull?
|
||||
}
|
||||
|
@ -36,7 +36,6 @@ import java.util.List;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.data.api.AppError;
|
||||
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;
|
||||
@ -54,7 +53,6 @@ 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.api.AppError.CODE_OTHER;
|
||||
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;
|
||||
@ -374,7 +372,8 @@ public class EventManualDialog {
|
||||
}
|
||||
} catch (Exception e) {
|
||||
activity.runOnUiThread(() -> {
|
||||
app.apiEdziennik.guiShowErrorDialog(activity, new AppError(TAG, 379, CODE_OTHER, null, e), R.string.error_occured);
|
||||
// TODO show error in EventManualDialog
|
||||
//app.apiEdziennik.guiShowErrorDialog(activity, new AppError(TAG, 379, CODE_OTHER, null, e), R.string.error_occured);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -30,7 +30,9 @@ class EventManualV2Dialog(
|
||||
val defaultDate: Date? = null,
|
||||
val defaultTime: Time? = null,
|
||||
val defaultType: Int? = null,
|
||||
val editingEvent: Event? = null
|
||||
val editingEvent: Event? = null,
|
||||
val onShowListener: ((tag: String) -> Unit)? = null,
|
||||
val onDismissListener: ((tag: String) -> Unit)? = null
|
||||
) : CoroutineScope {
|
||||
|
||||
companion object {
|
||||
@ -48,14 +50,19 @@ class EventManualV2Dialog(
|
||||
private var defaultLoaded = false
|
||||
|
||||
init { run {
|
||||
if (activity.isFinishing)
|
||||
return@run
|
||||
job = Job()
|
||||
|
||||
onShowListener?.invoke(TAG)
|
||||
b = DialogEventManualV2Binding.inflate(activity.layoutInflater)
|
||||
dialog = MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.dialog_event_manual_title)
|
||||
.setView(b.root)
|
||||
.setNegativeButton(R.string.cancel) { dialog, _ -> dialog.dismiss() }
|
||||
.setPositiveButton(R.string.save) { _, _ -> saveEvent() }
|
||||
.setOnDismissListener {
|
||||
onDismissListener?.invoke(TAG)
|
||||
}
|
||||
.show()
|
||||
|
||||
event = editingEvent?.clone() ?: Event().also { event ->
|
||||
|
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-13.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.dialogs.settings
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.coroutines.*
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.databinding.DialogLessonDetailsBinding
|
||||
import pl.szczodrzynski.edziennik.utils.models.Notification
|
||||
import java.util.*
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class ProfileRemoveDialog(
|
||||
val activity: MainActivity,
|
||||
val profileId: Int,
|
||||
val profileName: String
|
||||
) : CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "ProfileRemoveDialog"
|
||||
}
|
||||
|
||||
private lateinit var job: Job
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
private val app by lazy { activity.application as App }
|
||||
private lateinit var b: DialogLessonDetailsBinding
|
||||
private lateinit var dialog: AlertDialog
|
||||
|
||||
init { run {
|
||||
job = Job()
|
||||
|
||||
dialog = MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.profile_menu_remove_confirm)
|
||||
.setMessage(activity.getString(R.string.profile_menu_remove_confirm_text_format, profileName, profileName))
|
||||
.setPositiveButton(R.string.remove) { _, _ ->
|
||||
removeProfile()
|
||||
}
|
||||
.setNeutralButton(R.string.cancel) { dialog, _ -> dialog.dismiss() }
|
||||
.setCancelable(false)
|
||||
.show()
|
||||
}}
|
||||
|
||||
private fun removeProfile() { launch {
|
||||
val deferred = async(Dispatchers.Default) {
|
||||
val profileObject = app.db.profileDao().getByIdNow(profileId) ?: return@async
|
||||
app.db.announcementDao().clear(profileId)
|
||||
app.db.attendanceDao().clear(profileId)
|
||||
app.db.eventDao().clear(profileId)
|
||||
app.db.eventTypeDao().clear(profileId)
|
||||
app.db.gradeDao().clear(profileId)
|
||||
app.db.gradeCategoryDao().clear(profileId)
|
||||
app.db.lessonDao().clear(profileId)
|
||||
app.db.lessonChangeDao().clear(profileId)
|
||||
app.db.luckyNumberDao().clear(profileId)
|
||||
app.db.noticeDao().clear(profileId)
|
||||
app.db.subjectDao().clear(profileId)
|
||||
app.db.teacherDao().clear(profileId)
|
||||
app.db.teamDao().clear(profileId)
|
||||
app.db.messageRecipientDao().clear(profileId)
|
||||
app.db.messageDao().clear(profileId)
|
||||
app.db.endpointTimerDao().clear(profileId)
|
||||
app.db.attendanceTypeDao().clear(profileId)
|
||||
app.db.classroomDao().clear(profileId)
|
||||
app.db.lessonRangeDao().clear(profileId)
|
||||
app.db.noticeTypeDao().clear(profileId)
|
||||
app.db.teacherAbsenceDao().clear(profileId)
|
||||
app.db.teacherAbsenceTypeDao().clear(profileId)
|
||||
app.db.timetableDao().clear(profileId)
|
||||
|
||||
val loginStoreId = profileObject.loginStoreId
|
||||
val profilesUsingLoginStore = app.db.profileDao().getIdsByLoginStoreIdNow(loginStoreId)
|
||||
if (profilesUsingLoginStore.size == 1) {
|
||||
app.db.loginStoreDao().remove(loginStoreId)
|
||||
}
|
||||
app.db.profileDao().remove(profileId)
|
||||
app.db.metadataDao().deleteAll(profileId)
|
||||
|
||||
val toRemove = ArrayList<Notification>()
|
||||
for (notification in app.appConfig.notifications) {
|
||||
if (notification.profileId == profileId) {
|
||||
toRemove.add(notification)
|
||||
}
|
||||
}
|
||||
app.appConfig.notifications.removeAll(toRemove)
|
||||
|
||||
app.profile = null
|
||||
App.profileId = -1
|
||||
|
||||
app.profileLoadById(app.profileLastId())
|
||||
}
|
||||
deferred.await()
|
||||
dialog.dismiss()
|
||||
activity.reloadTarget()
|
||||
Toast.makeText(activity, R.string.dialog_profile_remove_success, Toast.LENGTH_LONG).show()
|
||||
}}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-13.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.dialogs.sync
|
||||
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
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.MainActivity
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.task.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.databinding.DialogLessonDetailsBinding
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class SyncViewListDialog(
|
||||
val activity: MainActivity,
|
||||
val currentViewId: Int? = null
|
||||
) : CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "SyncViewListDialog"
|
||||
}
|
||||
|
||||
private lateinit var job: Job
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
private val app by lazy { activity.application as App }
|
||||
private lateinit var b: DialogLessonDetailsBinding
|
||||
private lateinit var dialog: AlertDialog
|
||||
|
||||
init { run {
|
||||
job = Job()
|
||||
|
||||
val viewIds = arrayOf(
|
||||
MainActivity.DRAWER_ITEM_TIMETABLE,
|
||||
MainActivity.DRAWER_ITEM_AGENDA,
|
||||
MainActivity.DRAWER_ITEM_GRADES,
|
||||
MainActivity.DRAWER_ITEM_HOMEWORK,
|
||||
MainActivity.DRAWER_ITEM_BEHAVIOUR,
|
||||
MainActivity.DRAWER_ITEM_ATTENDANCE,
|
||||
MainActivity.DRAWER_ITEM_MESSAGES,
|
||||
MainActivity.DRAWER_ITEM_MESSAGES,
|
||||
MainActivity.DRAWER_ITEM_ANNOUNCEMENTS
|
||||
)
|
||||
|
||||
val items = arrayOf<String>(
|
||||
app.getString(R.string.menu_timetable),
|
||||
app.getString(R.string.menu_agenda),
|
||||
app.getString(R.string.menu_grades),
|
||||
app.getString(R.string.menu_homework),
|
||||
app.getString(R.string.menu_notices),
|
||||
app.getString(R.string.menu_attendance),
|
||||
app.getString(R.string.title_messages_inbox_single),
|
||||
app.getString(R.string.title_messages_sent_single),
|
||||
app.getString(R.string.menu_announcements)
|
||||
)
|
||||
|
||||
val everything = currentViewId == MainActivity.DRAWER_ITEM_HOME
|
||||
val checkedItems = booleanArrayOf(
|
||||
everything || currentViewId == MainActivity.DRAWER_ITEM_TIMETABLE,
|
||||
everything || currentViewId == MainActivity.DRAWER_ITEM_AGENDA,
|
||||
everything || currentViewId == MainActivity.DRAWER_ITEM_GRADES,
|
||||
everything || currentViewId == MainActivity.DRAWER_ITEM_HOMEWORK,
|
||||
everything || currentViewId == MainActivity.DRAWER_ITEM_BEHAVIOUR,
|
||||
everything || currentViewId == MainActivity.DRAWER_ITEM_ATTENDANCE,
|
||||
everything || currentViewId == MainActivity.DRAWER_ITEM_MESSAGES && MessagesFragment.pageSelection != 1,
|
||||
everything || currentViewId == MainActivity.DRAWER_ITEM_MESSAGES && MessagesFragment.pageSelection == 1,
|
||||
everything || currentViewId == MainActivity.DRAWER_ITEM_ANNOUNCEMENTS
|
||||
)
|
||||
val userChooses = checkedItems.toMutableList()
|
||||
|
||||
dialog = MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.dialog_sync_view_list_title)
|
||||
.setMultiChoiceItems(items, checkedItems) { _, which, isChecked ->
|
||||
userChooses[which] = isChecked
|
||||
}
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
dialog.dismiss()
|
||||
|
||||
val selectedViewIds = userChooses.mapIndexed { index, it ->
|
||||
if (it)
|
||||
viewIds[index] to when (index) {
|
||||
7 -> 1
|
||||
else -> 0
|
||||
}
|
||||
else
|
||||
null
|
||||
}.let {
|
||||
listOfNotNull(*it.toTypedArray())
|
||||
}
|
||||
|
||||
activity.swipeRefreshLayout.isRefreshing = true
|
||||
EdziennikTask.syncProfile(
|
||||
App.profileId,
|
||||
selectedViewIds
|
||||
).enqueue(activity)
|
||||
}
|
||||
.setNegativeButton(R.string.cancel) { _, _ ->
|
||||
dialog.dismiss()
|
||||
}
|
||||
.show()
|
||||
}}
|
||||
}
|
@ -21,7 +21,9 @@ import pl.szczodrzynski.edziennik.utils.models.Week
|
||||
|
||||
class LessonDetailsDialog(
|
||||
val activity: AppCompatActivity,
|
||||
val lesson: LessonFull
|
||||
val lesson: LessonFull,
|
||||
val onShowListener: ((tag: String) -> Unit)? = null,
|
||||
val onDismissListener: ((tag: String) -> Unit)? = null
|
||||
) {
|
||||
companion object {
|
||||
private const val TAG = "LessonDetailsDialog"
|
||||
@ -31,6 +33,9 @@ class LessonDetailsDialog(
|
||||
private lateinit var dialog: AlertDialog
|
||||
|
||||
init { run {
|
||||
if (activity.isFinishing)
|
||||
return@run
|
||||
onShowListener?.invoke(TAG)
|
||||
b = DialogLessonDetailsBinding.inflate(activity.layoutInflater)
|
||||
dialog = MaterialAlertDialogBuilder(activity)
|
||||
.setView(b.root)
|
||||
@ -38,8 +43,13 @@ class LessonDetailsDialog(
|
||||
dialog.dismiss()
|
||||
}
|
||||
.setNeutralButton(R.string.add) { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
EventManualV2Dialog(activity, lesson.profileId, lesson)
|
||||
EventManualV2Dialog(
|
||||
activity,
|
||||
lesson.profileId,
|
||||
lesson,
|
||||
onShowListener = onShowListener,
|
||||
onDismissListener = onDismissListener
|
||||
)
|
||||
/*MaterialAlertDialogBuilder(activity)
|
||||
.setItems(R.array.main_menu_add_options) { dialog2, which ->
|
||||
dialog2.dismiss()
|
||||
@ -59,6 +69,9 @@ class LessonDetailsDialog(
|
||||
.setNegativeButton(R.string.cancel) { dialog2, _ -> dialog2.dismiss() }
|
||||
.show()*/
|
||||
}
|
||||
.setOnDismissListener {
|
||||
onDismissListener?.invoke(TAG)
|
||||
}
|
||||
.show()
|
||||
update()
|
||||
}}
|
||||
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-13.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.error
|
||||
|
||||
import android.util.Log
|
||||
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 pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.databinding.DialogLessonDetailsBinding
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class ErrorDialog(
|
||||
val activity: AppCompatActivity,
|
||||
val exception: Exception
|
||||
) : CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "ErrorDialog"
|
||||
}
|
||||
|
||||
private lateinit var job: Job
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
private val app by lazy { activity.application as App }
|
||||
private lateinit var b: DialogLessonDetailsBinding
|
||||
private lateinit var dialog: AlertDialog
|
||||
|
||||
init { run {
|
||||
job = Job()
|
||||
|
||||
dialog = MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.error_occured)
|
||||
.setMessage(exception.message + "\n" + Log.getStackTraceString(exception))
|
||||
.setPositiveButton(R.string.ok) { _, _ ->
|
||||
dialog.dismiss()
|
||||
}
|
||||
.show()
|
||||
}}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-13.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.ui.modules.error
|
||||
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.navlib.getColorFromAttr
|
||||
|
||||
class ErrorSnackbar(val activity: AppCompatActivity) {
|
||||
companion object {
|
||||
private const val TAG = "ErrorSnackbar"
|
||||
}
|
||||
|
||||
private var snackbar: Snackbar? = null
|
||||
private lateinit var coordinator: CoordinatorLayout
|
||||
private val errors = mutableListOf<ApiError>()
|
||||
|
||||
fun setCoordinator(coordinatorLayout: CoordinatorLayout, showAbove: View? = null) {
|
||||
this.coordinator = coordinatorLayout
|
||||
snackbar = Snackbar.make(coordinator, R.string.snackbar_error_text, Snackbar.LENGTH_INDEFINITE)
|
||||
snackbar?.setAction(R.string.more) {
|
||||
|
||||
}
|
||||
val bgColor = ColorUtils.compositeColors(
|
||||
getColorFromAttr(activity, R.attr.colorOnSurface) and 0xcfffffff.toInt(),
|
||||
getColorFromAttr(activity, R.attr.colorSurface)
|
||||
)
|
||||
snackbar?.setBackgroundTint(bgColor)
|
||||
showAbove?.let { snackbar?.anchorView = it }
|
||||
}
|
||||
|
||||
fun addError(apiError: ApiError): ErrorSnackbar {
|
||||
errors += apiError
|
||||
snackbar?.setText(apiError.getStringReason(activity))
|
||||
return this
|
||||
}
|
||||
|
||||
fun show() = snackbar?.show()
|
||||
fun dismiss() = snackbar?.dismiss()
|
||||
}
|
@ -15,8 +15,9 @@ import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.data.api.AppError;
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError;
|
||||
import pl.szczodrzynski.edziennik.databinding.ActivityLoginBinding;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar;
|
||||
|
||||
public class LoginActivity extends AppCompatActivity {
|
||||
|
||||
@ -26,7 +27,8 @@ public class LoginActivity extends AppCompatActivity {
|
||||
public static final int RESULT_OK = 1;
|
||||
public static NavOptions navOptions;
|
||||
|
||||
static AppError error = null;
|
||||
static ApiError error = null;
|
||||
ErrorSnackbar errorSnackbar = new ErrorSnackbar(this);
|
||||
|
||||
static List<LoginProfileObject> profileObjects;
|
||||
public static boolean firstCompleted = false; // if a profile is already added during *this* login. This means that LoginChooser has to navigateUp onBackPressed. Else, finish the activity.
|
||||
@ -69,6 +71,8 @@ public class LoginActivity extends AppCompatActivity {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setTheme(R.style.AppTheme_Light);
|
||||
|
||||
firstCompleted = false;
|
||||
profileObjects = new ArrayList<>();
|
||||
error = null;
|
||||
@ -83,6 +87,8 @@ public class LoginActivity extends AppCompatActivity {
|
||||
b = DataBindingUtil.inflate(getLayoutInflater(), R.layout.activity_login, null, false);
|
||||
setContentView(b.getRoot());
|
||||
|
||||
errorSnackbar.setCoordinator(b.coordinator, null);
|
||||
|
||||
app = (App) getApplication();
|
||||
|
||||
if (!app.appConfig.loginFinished) {
|
||||
|
@ -1,25 +1,23 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import android.text.Editable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.danimahardhika.cafebar.CafeBar;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.data.api.AppError;
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginIuczniowieBinding;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.data.api.AppError.CODE_INVALID_LOGIN;
|
||||
import static pl.szczodrzynski.edziennik.data.api.AppError.CODE_INVALID_SCHOOL_NAME;
|
||||
@ -31,6 +29,7 @@ public class LoginIuczniowieFragment extends Fragment {
|
||||
private NavController nav;
|
||||
private FragmentLoginIuczniowieBinding b;
|
||||
private static final String TAG = "LoginIuczniowie";
|
||||
private ErrorSnackbar errorSnackbar;
|
||||
|
||||
public LoginIuczniowieFragment() { }
|
||||
|
||||
@ -40,6 +39,7 @@ public class LoginIuczniowieFragment extends Fragment {
|
||||
if (getActivity() != null) {
|
||||
app = (App) getActivity().getApplicationContext();
|
||||
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
|
||||
errorSnackbar = ((LoginActivity) getActivity()).errorSnackbar;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
@ -54,31 +54,17 @@ public class LoginIuczniowieFragment extends Fragment {
|
||||
assert getActivity() != null;
|
||||
|
||||
view.postDelayed(() -> {
|
||||
AppError error = LoginActivity.error;
|
||||
ApiError error = LoginActivity.error;
|
||||
if (error != null) {
|
||||
switch (error.errorCode) {
|
||||
switch (error.getErrorCode()) {
|
||||
case CODE_INVALID_SCHOOL_NAME:
|
||||
b.loginSchoolNameLayout.setError(getString(R.string.login_error_incorrect_school_name));
|
||||
break;
|
||||
case CODE_INVALID_LOGIN:
|
||||
b.loginPasswordLayout.setError(getString(R.string.login_error_incorrect_login_or_password));
|
||||
break;
|
||||
default:
|
||||
CafeBar.builder(getActivity())
|
||||
.to(b.root)
|
||||
.content(getString(R.string.login_error, error.asReadableString(getActivity())))
|
||||
.autoDismiss(false)
|
||||
.positiveText(R.string.ok)
|
||||
.onPositive(CafeBar::dismiss)
|
||||
.floating(true)
|
||||
.swipeToDismiss(true)
|
||||
.neutralText(R.string.more)
|
||||
.onNeutral(cafeBar -> app.apiEdziennik.guiShowErrorDialog(getActivity(), error, R.string.error_details))
|
||||
.negativeText(R.string.report)
|
||||
.onNegative((cafeBar -> app.apiEdziennik.guiReportError(getActivity(), error, null)))
|
||||
.show();
|
||||
break;
|
||||
}
|
||||
errorSnackbar.addError(error).show();
|
||||
LoginActivity.error = null;
|
||||
}
|
||||
}, 100);
|
||||
|
@ -1,28 +1,26 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import android.text.Editable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.danimahardhika.cafebar.CafeBar;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.data.api.AppError;
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginLibrusBinding;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.data.api.AppError.CODE_INVALID_LOGIN;
|
||||
import static pl.szczodrzynski.edziennik.data.api.AppError.CODE_LIBRUS_NOT_ACTIVATED;
|
||||
import static pl.szczodrzynski.edziennik.api.v2.ErrorsKt.ERROR_LOGIN_DATA_INVALID;
|
||||
import static pl.szczodrzynski.edziennik.api.v2.ErrorsKt.ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED;
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_LIBRUS;
|
||||
|
||||
public class LoginLibrusFragment extends Fragment {
|
||||
@ -31,6 +29,7 @@ public class LoginLibrusFragment extends Fragment {
|
||||
private NavController nav;
|
||||
private FragmentLoginLibrusBinding b;
|
||||
private static final String TAG = "LoginLibrus";
|
||||
private ErrorSnackbar errorSnackbar;
|
||||
|
||||
public LoginLibrusFragment() { }
|
||||
|
||||
@ -40,6 +39,7 @@ public class LoginLibrusFragment extends Fragment {
|
||||
if (getActivity() != null) {
|
||||
app = (App) getActivity().getApplicationContext();
|
||||
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
|
||||
errorSnackbar = ((LoginActivity) getActivity()).errorSnackbar;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
@ -54,32 +54,17 @@ public class LoginLibrusFragment extends Fragment {
|
||||
assert getActivity() != null;
|
||||
|
||||
view.postDelayed(() -> {
|
||||
AppError error = LoginActivity.error;
|
||||
ApiError error = LoginActivity.error;
|
||||
if (error != null) {
|
||||
switch (error.errorCode) {
|
||||
case CODE_INVALID_LOGIN:
|
||||
switch (error.getErrorCode()) {
|
||||
case ERROR_LOGIN_DATA_INVALID:
|
||||
b.loginPasswordLayout.setError(getString(R.string.login_error_incorrect_login_or_password));
|
||||
break;
|
||||
case CODE_LIBRUS_NOT_ACTIVATED:
|
||||
case ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED:
|
||||
b.loginEmailLayout.setError(getString(R.string.login_error_account_not_activated));
|
||||
break;
|
||||
default:
|
||||
CafeBar.builder(getActivity())
|
||||
.to(b.root)
|
||||
.content(getString(R.string.login_error, error.asReadableString(getActivity())))
|
||||
.duration(10000)
|
||||
.autoDismiss(false)
|
||||
.positiveText(R.string.ok)
|
||||
.onPositive(CafeBar::dismiss)
|
||||
.floating(true)
|
||||
.swipeToDismiss(true)
|
||||
.neutralText(R.string.more)
|
||||
.onNeutral(cafeBar -> app.apiEdziennik.guiShowErrorDialog(getActivity(), error, R.string.error_details))
|
||||
.negativeText(R.string.report)
|
||||
.onNegative((cafeBar -> app.apiEdziennik.guiReportError(getActivity(), error, null)))
|
||||
.show();
|
||||
break;
|
||||
}
|
||||
errorSnackbar.addError(error).show();
|
||||
LoginActivity.error = null;
|
||||
}
|
||||
}, 100);
|
||||
|
@ -1,23 +1,23 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import android.text.Editable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.danimahardhika.cafebar.CafeBar;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.data.api.AppError;
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginMobidziennikBinding;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.data.api.AppError.CODE_ARCHIVED;
|
||||
import static pl.szczodrzynski.edziennik.data.api.AppError.CODE_INVALID_LOGIN;
|
||||
@ -31,6 +31,7 @@ public class LoginMobidziennikFragment extends Fragment {
|
||||
private NavController nav;
|
||||
private FragmentLoginMobidziennikBinding b;
|
||||
private static final String TAG = "LoginMobidziennik";
|
||||
private ErrorSnackbar errorSnackbar;
|
||||
|
||||
public LoginMobidziennikFragment() { }
|
||||
|
||||
@ -40,6 +41,7 @@ public class LoginMobidziennikFragment extends Fragment {
|
||||
if (getActivity() != null) {
|
||||
app = (App) getActivity().getApplicationContext();
|
||||
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
|
||||
errorSnackbar = ((LoginActivity) getActivity()).errorSnackbar;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
@ -54,9 +56,9 @@ public class LoginMobidziennikFragment extends Fragment {
|
||||
assert getActivity() != null;
|
||||
|
||||
view.postDelayed(() -> {
|
||||
AppError error = LoginActivity.error;
|
||||
ApiError error = LoginActivity.error;
|
||||
if (error != null) {
|
||||
switch (error.errorCode) {
|
||||
switch (error.getErrorCode()) {
|
||||
case CODE_INVALID_LOGIN:
|
||||
b.loginPasswordLayout.setError(getString(R.string.login_error_incorrect_login_or_password));
|
||||
break;
|
||||
@ -69,22 +71,8 @@ public class LoginMobidziennikFragment extends Fragment {
|
||||
case CODE_INVALID_SERVER_ADDRESS:
|
||||
b.loginServerAddressLayout.setError(getString(R.string.login_error_incorrect_address));
|
||||
break;
|
||||
default:
|
||||
CafeBar.builder(getActivity())
|
||||
.to(b.root)
|
||||
.content(getString(R.string.login_error, error.asReadableString(getActivity())))
|
||||
.autoDismiss(false)
|
||||
.positiveText(R.string.ok)
|
||||
.onPositive(CafeBar::dismiss)
|
||||
.floating(true)
|
||||
.swipeToDismiss(true)
|
||||
.neutralText(R.string.more)
|
||||
.onNeutral(cafeBar -> app.apiEdziennik.guiShowErrorDialog(getActivity(), error, R.string.error_details))
|
||||
.negativeText(R.string.report)
|
||||
.onNegative((cafeBar -> app.apiEdziennik.guiReportError(getActivity(), error, null)))
|
||||
.show();
|
||||
break;
|
||||
}
|
||||
errorSnackbar.addError(error).show();
|
||||
LoginActivity.error = null;
|
||||
}
|
||||
}, 100);
|
||||
|
@ -23,11 +23,11 @@ import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.ApiTaskErrorEvent;
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.FirstLoginFinishedEvent;
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.task.EdziennikTask;
|
||||
import pl.szczodrzynski.edziennik.data.api.AppError;
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginProgressBinding;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.data.api.AppError.CODE_OTHER;
|
||||
import static pl.szczodrzynski.edziennik.api.v2.ErrorsKt.LOGIN_NO_ARGUMENTS;
|
||||
|
||||
public class LoginProgressFragment extends Fragment {
|
||||
|
||||
@ -62,7 +62,7 @@ public class LoginProgressFragment extends Fragment {
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onSyncErrorEvent(ApiTaskErrorEvent event) {
|
||||
LoginActivity.error = event.getError().toAppError();
|
||||
LoginActivity.error = event.getError();
|
||||
if (getActivity() == null)
|
||||
return;
|
||||
nav.navigateUp();
|
||||
@ -79,7 +79,7 @@ public class LoginProgressFragment extends Fragment {
|
||||
LoginActivity.error = null;
|
||||
|
||||
if (args == null) {
|
||||
LoginActivity.error = new AppError(TAG, 72, CODE_OTHER, getString(R.string.login_error_no_arguments));
|
||||
LoginActivity.error = new ApiError(TAG, LOGIN_NO_ARGUMENTS);
|
||||
nav.navigateUp();
|
||||
return;
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@ -8,14 +11,11 @@ import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginSyncErrorBinding;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
public class LoginSyncErrorFragment extends Fragment {
|
||||
|
||||
private App app;
|
||||
@ -44,10 +44,10 @@ public class LoginSyncErrorFragment extends Fragment {
|
||||
assert getContext() != null;
|
||||
assert getActivity() != null;
|
||||
|
||||
b.errorDetails.setText(LoginActivity.error == null ? "" : LoginActivity.error.asReadableString(getActivity()));
|
||||
b.errorDetails.setText(LoginActivity.error == null ? "" : LoginActivity.error.getStringReason(getActivity()));
|
||||
|
||||
b.reportButton.setOnClickListener((v -> {
|
||||
app.apiEdziennik.guiReportError(getActivity(), LoginActivity.error, null);
|
||||
// TODO error report activity open here app.apiEdziennik.guiReportError(getActivity(), LoginActivity.error, null);
|
||||
}));
|
||||
|
||||
b.nextButton.setOnClickListener((v -> {
|
||||
|
@ -65,7 +65,7 @@ class LoginSyncFragment : Fragment() {
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onSyncErrorEvent(event: ApiTaskErrorEvent) {
|
||||
LoginActivity.error = event.error.toAppError()
|
||||
LoginActivity.error = event.error
|
||||
nav.navigate(R.id.loginSyncErrorFragment, null, LoginActivity.navOptions)
|
||||
}
|
||||
|
||||
|
@ -3,27 +3,24 @@ package pl.szczodrzynski.edziennik.ui.modules.login;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import android.text.Editable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.danimahardhika.cafebar.CafeBar;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
|
||||
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 androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.regex.Matcher;
|
||||
@ -36,9 +33,10 @@ import javax.crypto.ShortBufferException;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.webpush.QrScannerActivity;
|
||||
import pl.szczodrzynski.edziennik.data.api.AppError;
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentLoginVulcanBinding;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.webpush.QrScannerActivity;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.data.api.AppError.CODE_EXPIRED_TOKEN;
|
||||
@ -53,6 +51,7 @@ public class LoginVulcanFragment extends Fragment {
|
||||
private NavController nav;
|
||||
private FragmentLoginVulcanBinding b;
|
||||
private static final String TAG = "LoginVulcan";
|
||||
private ErrorSnackbar errorSnackbar;
|
||||
|
||||
public LoginVulcanFragment() { }
|
||||
|
||||
@ -62,6 +61,7 @@ public class LoginVulcanFragment extends Fragment {
|
||||
if (getActivity() != null) {
|
||||
app = (App) getActivity().getApplicationContext();
|
||||
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
|
||||
errorSnackbar = ((LoginActivity) getActivity()).errorSnackbar;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
@ -76,9 +76,9 @@ public class LoginVulcanFragment extends Fragment {
|
||||
assert getActivity() != null;
|
||||
|
||||
view.postDelayed(() -> {
|
||||
AppError error = LoginActivity.error;
|
||||
ApiError error = LoginActivity.error;
|
||||
if (error != null) {
|
||||
switch (error.errorCode) {
|
||||
switch (error.getErrorCode()) {
|
||||
case CODE_INVALID_TOKEN:
|
||||
b.loginTokenLayout.setError(getString(R.string.login_error_incorrect_token));
|
||||
break;
|
||||
@ -89,28 +89,14 @@ public class LoginVulcanFragment extends Fragment {
|
||||
b.loginSymbolLayout.setError(getString(R.string.login_error_incorrect_symbol));
|
||||
break;
|
||||
case CODE_INVALID_PIN:
|
||||
if (!"?".equals(error.errorText)) {
|
||||
/*if (!"?".equals(error.errorText)) {
|
||||
b.loginPinLayout.setError(getString(R.string.login_error_incorrect_pin_format, error.errorText));
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
b.loginPinLayout.setError(getString(R.string.login_error_incorrect_pin));
|
||||
break;
|
||||
default:
|
||||
CafeBar.builder(getActivity())
|
||||
.to(b.root)
|
||||
.content(getString(R.string.login_error, error.asReadableString(getActivity())))
|
||||
.autoDismiss(false)
|
||||
.positiveText(R.string.ok)
|
||||
.onPositive(CafeBar::dismiss)
|
||||
.floating(true)
|
||||
.swipeToDismiss(true)
|
||||
.neutralText(R.string.more)
|
||||
.onNeutral(cafeBar -> app.apiEdziennik.guiShowErrorDialog(getActivity(), error, R.string.error_details))
|
||||
.negativeText(R.string.report)
|
||||
.onNegative((cafeBar -> app.apiEdziennik.guiReportError(getActivity(), error, null)))
|
||||
.show();
|
||||
break;
|
||||
}
|
||||
errorSnackbar.addError(error).show();
|
||||
LoginActivity.error = null;
|
||||
}
|
||||
}, 100);
|
||||
|
@ -97,7 +97,7 @@ class MessageFragment : Fragment(), CoroutineScope {
|
||||
val msg = app.db.messageDao().getById(App.profileId, messageId)?.also {
|
||||
it.recipients = app.db.messageRecipientDao().getAllByMessageId(it.profileId, it.id)
|
||||
if (it.body != null && !it.seen) {
|
||||
app.db.metadataDao().setSeen(it.profileId, message, true)
|
||||
app.db.metadataDao().setSeen(it.profileId, it, true)
|
||||
}
|
||||
}
|
||||
msg
|
||||
|
@ -4,7 +4,6 @@ import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MotionEvent;
|
||||
@ -13,7 +12,6 @@ import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
@ -35,12 +33,6 @@ import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.data.api.AppError;
|
||||
import pl.szczodrzynski.edziennik.data.api.Edziennik;
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.SyncCallback;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore;
|
||||
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.teachers.Teacher;
|
||||
import pl.szczodrzynski.edziennik.databinding.ActivityComposeMessageBinding;
|
||||
import pl.szczodrzynski.edziennik.utils.Colors;
|
||||
@ -63,7 +55,7 @@ public class MessagesComposeActivity extends AppCompatActivity {
|
||||
b = DataBindingUtil.inflate(getLayoutInflater(), R.layout.activity_compose_message, null, false);
|
||||
setContentView(b.getRoot());
|
||||
|
||||
composeInfo = Edziennik.getApi(app, app.profile.getLoginStoreType()).getComposeInfo(app.profile);
|
||||
/*composeInfo = Edziennik.getApi(app, app.profile.getLoginStoreType()).getComposeInfo(app.profile);
|
||||
|
||||
Toolbar toolbar = b.toolbar;
|
||||
setSupportActionBar(toolbar);
|
||||
@ -99,7 +91,7 @@ public class MessagesComposeActivity extends AppCompatActivity {
|
||||
MessagesComposeSuggestionAdapter adapter = new MessagesComposeSuggestionAdapter(this, teachers);
|
||||
//ArrayAdapter<Teacher> adapter = new ArrayAdapter<>(this, android.R.layout.simple_dropdown_item_1line, teachers);
|
||||
b.nachoTextView.setAdapter(adapter);
|
||||
});
|
||||
});*/
|
||||
/*app.db.teacherDao().getAllTeachers(App.profileId).observe(this, teachers -> {
|
||||
|
||||
});*/
|
||||
|
@ -1,17 +1,12 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.messages;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.media.ThumbnailUtils;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.text.Html;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@ -19,12 +14,18 @@ import android.widget.FrameLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
|
||||
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.google.android.material.chip.Chip;
|
||||
import com.mikepenz.iconics.IconicsColor;
|
||||
import com.mikepenz.iconics.IconicsDrawable;
|
||||
import com.mikepenz.iconics.IconicsSize;
|
||||
import com.mikepenz.iconics.typeface.IIcon;
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial;
|
||||
import com.theartofdev.edmodo.cropper.CropImage;
|
||||
|
||||
@ -39,36 +40,16 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
|
||||
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import im.wangchao.mhttp.Response;
|
||||
import im.wangchao.mhttp.callback.FileCallbackHandler;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.data.api.Edziennik;
|
||||
import pl.szczodrzynski.edziennik.data.api.AppError;
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.SyncCallback;
|
||||
import pl.szczodrzynski.edziennik.databinding.MessagesDetailsBinding;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipientFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileFull;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
import pl.szczodrzynski.edziennik.utils.Anim;
|
||||
import pl.szczodrzynski.edziennik.databinding.MessagesDetailsBinding;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorDialog;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
import static android.view.Gravity.CENTER_VERTICAL;
|
||||
import static android.view.Gravity.END;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.getResizedBitmap;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.getStringFromFile;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.readableFileSize;
|
||||
@ -108,7 +89,7 @@ public class MessagesDetailsFragment extends Fragment {
|
||||
|
||||
b.messageContent.setVisibility(View.GONE);
|
||||
|
||||
if (messageId != -1) {
|
||||
/*if (messageId != -1) {
|
||||
AsyncTask.execute(() -> {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
@ -286,7 +267,7 @@ public class MessagesDetailsFragment extends Fragment {
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
}*/
|
||||
|
||||
// click to expand subject and sender
|
||||
b.messageSubject.setOnClickListener(v -> {
|
||||
@ -340,7 +321,7 @@ public class MessagesDetailsFragment extends Fragment {
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
app.apiEdziennik.guiReportException(activity, 355, e);
|
||||
new ErrorDialog(activity, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -359,7 +340,7 @@ public class MessagesDetailsFragment extends Fragment {
|
||||
|
||||
File storageDir = Utils.getStorageDir();
|
||||
|
||||
Edziennik.getApi(app, app.profile.getLoginStoreType()).getAttachment(activity, new SyncCallback() {
|
||||
/*Edziennik.getApi(app, app.profile.getLoginStoreType()).getAttachment(activity, new SyncCallback() {
|
||||
@Override
|
||||
public void onLoginFirst(List<Profile> profileList, LoginStore loginStore) {
|
||||
|
||||
@ -437,7 +418,7 @@ public class MessagesDetailsFragment extends Fragment {
|
||||
}
|
||||
})
|
||||
.build()
|
||||
.enqueue());
|
||||
.enqueue());*/
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.POSTING)
|
||||
@ -478,7 +459,7 @@ public class MessagesDetailsFragment extends Fragment {
|
||||
.positiveText(R.string.ok)
|
||||
.neutralColor(R.string.report)
|
||||
.onNeutral((dialog, which) -> {
|
||||
app.apiEdziennik.guiReportException(activity, 433, event.exception);
|
||||
new ErrorDialog(activity, event.exception);
|
||||
})
|
||||
.show();
|
||||
}
|
||||
@ -486,7 +467,7 @@ public class MessagesDetailsFragment extends Fragment {
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
app.apiEdziennik.guiReportException(activity, 425, e);
|
||||
new ErrorDialog(activity, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,474 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.messages;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.DownloadManager;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.provider.MediaStore;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.webkit.CookieManager;
|
||||
import android.webkit.MimeTypeMap;
|
||||
import android.webkit.ValueCallback;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebResourceError;
|
||||
import android.webkit.WebResourceRequest;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.FileProvider;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.afollestad.materialdialogs.StackingBehavior;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentMessagesWebBinding;
|
||||
import pl.szczodrzynski.edziennik.utils.Anim;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
import static android.content.Context.DOWNLOAD_SERVICE;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.readableFileSize;
|
||||
|
||||
public class MessagesWebFragment extends Fragment {
|
||||
|
||||
private static final String TAG = "RegisterMessagesWeb";
|
||||
private App app = null;
|
||||
private Activity activity = null;
|
||||
private FragmentMessagesWebBinding b = null;
|
||||
|
||||
private WebView webView;
|
||||
private ProgressBar progressBar;
|
||||
private TextView error;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
activity = getActivity();
|
||||
if (getActivity() == null || getContext() == null)
|
||||
return null;
|
||||
app = (App) activity.getApplication();
|
||||
getContext().getTheme().applyStyle(Themes.INSTANCE.getAppTheme(), true);
|
||||
if (app.profile == null)
|
||||
return inflater.inflate(R.layout.fragment_loading, container, false);
|
||||
// activity, context and profile is valid
|
||||
b = DataBindingUtil.inflate(inflater, R.layout.fragment_messages_web, container, false);
|
||||
return b.getRoot();
|
||||
}
|
||||
|
||||
private boolean isStoragePermissionGranted(Activity a) {
|
||||
if (Build.VERSION.SDK_INT >= 23) {
|
||||
if (a.checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
== PackageManager.PERMISSION_GRANTED) {
|
||||
Log.v(TAG,"Permission is granted");
|
||||
return true;
|
||||
} else {
|
||||
|
||||
Log.v(TAG,"Permission is revoked");
|
||||
ActivityCompat.requestPermissions(a, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else { //permission is automatically granted on sdk<23 upon installation
|
||||
Log.v(TAG,"Permission is granted");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private String getFileNameFromDisposition(String header)
|
||||
{
|
||||
return header.substring(header.indexOf("\"") + 1, header.lastIndexOf("\""));
|
||||
}
|
||||
|
||||
private File downloadingFile;
|
||||
|
||||
private void enqueueFile(String url, String filename, File downloadingFile, String cookieString) {
|
||||
|
||||
this.downloadingFile = downloadingFile;
|
||||
|
||||
long downloadReference;
|
||||
|
||||
DownloadManager downloadManager;
|
||||
downloadManager = (DownloadManager)app.getSystemService(DOWNLOAD_SERVICE);
|
||||
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
|
||||
request.setTitle(filename);
|
||||
request.setDescription(getString(R.string.downloading));
|
||||
request.addRequestHeader("Cookie", cookieString);
|
||||
try {
|
||||
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename);
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
Toast.makeText(app, "Failed to get external storage files directory", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
downloadReference = downloadManager.enqueue(request);
|
||||
}
|
||||
|
||||
private static String getMimeType(String url) {
|
||||
String type = null;
|
||||
String extension = MimeTypeMap.getFileExtensionFromUrl(url);
|
||||
if (extension != null) {
|
||||
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
private void openFile(File url) {
|
||||
Toast.makeText(app, getString(R.string.opening_file, url.getName()), Toast.LENGTH_SHORT).show();
|
||||
try {
|
||||
Uri uri = FileProvider.getUriForFile(app, app.getApplicationContext().getPackageName() + ".provider", url);
|
||||
//Uri uri = Uri.fromFile(url);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
if (url.toString().contains(".doc") || url.toString().contains(".docx")) {
|
||||
// Word document
|
||||
intent.setDataAndType(uri, "application/msword");
|
||||
} else if (url.toString().contains(".pdf")) {
|
||||
// PDF file
|
||||
intent.setDataAndType(uri, "application/pdf");
|
||||
} else if (url.toString().contains(".ppt") || url.toString().contains(".pptx")) {
|
||||
// Powerpoint file
|
||||
intent.setDataAndType(uri, "application/vnd.ms-powerpoint");
|
||||
} else if (url.toString().contains(".xls") || url.toString().contains(".xlsx")) {
|
||||
// Excel file
|
||||
intent.setDataAndType(uri, "application/vnd.ms-excel");
|
||||
} else if (url.toString().contains(".zip") || url.toString().contains(".rar")) {
|
||||
// WAV audio file
|
||||
intent.setDataAndType(uri, "application/x-wav");
|
||||
} else if (url.toString().contains(".rtf")) {
|
||||
// RTF file
|
||||
intent.setDataAndType(uri, "application/rtf");
|
||||
} else if (url.toString().contains(".wav") || url.toString().contains(".mp3")) {
|
||||
// WAV audio file
|
||||
intent.setDataAndType(uri, "audio/x-wav");
|
||||
} else if (url.toString().contains(".gif")) {
|
||||
// GIF file
|
||||
intent.setDataAndType(uri, "image/gif");
|
||||
} else if (url.toString().contains(".jpg") || url.toString().contains(".jpeg") || url.toString().contains(".png")) {
|
||||
// JPG file
|
||||
intent.setDataAndType(uri, "image/jpeg");
|
||||
} else if (url.toString().contains(".txt")) {
|
||||
// Text file
|
||||
intent.setDataAndType(uri, "text/plain");
|
||||
} else if (url.toString().contains(".3gp") || url.toString().contains(".mpg") ||
|
||||
url.toString().contains(".mpeg") || url.toString().contains(".mpe") || url.toString().contains(".mp4") || url.toString().contains(".avi")) {
|
||||
// Video files
|
||||
intent.setDataAndType(uri, "video/*");
|
||||
} else {
|
||||
intent.setDataAndType(uri, "*/*");
|
||||
}
|
||||
|
||||
intent.setDataAndType(uri, getMimeType(uri.toString()));
|
||||
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
|
||||
app.startActivity(intent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Toast.makeText(app, R.string.opening_file_no_app, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void downloadFile(Activity a, String url, String filename, long contentLength, String cookieString) {
|
||||
if (!isStoragePermissionGranted(a))
|
||||
return;
|
||||
new MaterialDialog.Builder(a)
|
||||
.title(R.string.downloading_file)
|
||||
.content(getString((R.string.download_file_question), filename, readableFileSize(contentLength)))
|
||||
.positiveText(R.string.yes)
|
||||
.negativeText(R.string.no)
|
||||
.onPositive((dialog, which) -> {
|
||||
File downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
|
||||
File existingFile = new File(downloadsDir, filename);
|
||||
if (existingFile.exists()) {
|
||||
new MaterialDialog.Builder(a)
|
||||
.title(R.string.downloading_file)
|
||||
.content(getString(R.string.downloading_file_exists_choose, filename))
|
||||
.stackingBehavior(StackingBehavior.ADAPTIVE)
|
||||
.positiveText(R.string.downloading_file_exists_overwrite)
|
||||
.negativeText(R.string.downloading_file_exists_open)
|
||||
.neutralText(R.string.downloading_file_exists_create_new)
|
||||
.onPositive(((dialog1, which1) -> {
|
||||
if (!existingFile.delete())
|
||||
{
|
||||
new MaterialDialog.Builder(a)
|
||||
.title(R.string.downloading_file)
|
||||
.content(R.string.downloading_file_cannot_remove)
|
||||
.positiveText(R.string.ok)
|
||||
.negativeText(R.string.cancel)
|
||||
.onPositive(((dialog2, which2) -> enqueueFile(url, filename, existingFile, cookieString)))
|
||||
.show();
|
||||
return;
|
||||
}
|
||||
enqueueFile(url, filename, existingFile, cookieString);
|
||||
}))
|
||||
.onNegative(((dialog1, which1) -> openFile(existingFile)))
|
||||
.onNeutral((dialog1, which1) -> enqueueFile(url, filename, existingFile, cookieString))
|
||||
.show();
|
||||
|
||||
return;
|
||||
}
|
||||
enqueueFile(url, filename, existingFile, cookieString);
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
private String photoPath;
|
||||
private ValueCallback<Uri> mUM;
|
||||
private ValueCallback<Uri[]> fileCallback;
|
||||
private final static int REQUEST_FILE_CHOOSER = 1;
|
||||
private boolean justLoaded = false;
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if(Build.VERSION.SDK_INT >= 21){
|
||||
Uri[] results = null;
|
||||
//Check if response is positive
|
||||
if(resultCode == RESULT_OK){
|
||||
if(requestCode == REQUEST_FILE_CHOOSER){
|
||||
if(null == fileCallback){
|
||||
return;
|
||||
}
|
||||
if(data == null){
|
||||
//Capture Photo if no image available
|
||||
if (photoPath != null) {
|
||||
results = new Uri[]{Uri.parse(photoPath)};
|
||||
}
|
||||
}else{
|
||||
String dataString = data.getDataString();
|
||||
if(dataString != null){
|
||||
results = new Uri[]{Uri.parse(dataString)};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fileCallback.onReceiveValue(results);
|
||||
fileCallback = null;
|
||||
} else {
|
||||
if (requestCode == REQUEST_FILE_CHOOSER) {
|
||||
if(null == mUM) return;
|
||||
Uri result = data == null || resultCode != RESULT_OK ? null : data.getData();
|
||||
mUM.onReceiveValue(result);
|
||||
mUM = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private File createImageFile() throws IOException{
|
||||
@SuppressLint("SimpleDateFormat") String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
||||
String imageFileName = "img_"+timeStamp+"_";
|
||||
File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
|
||||
return File.createTempFile(imageFileName,".jpg",storageDir);
|
||||
}
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
webView = b.messagesWebView;
|
||||
progressBar = b.messagesWebProgressBar;
|
||||
error = b.messagesWebError;
|
||||
|
||||
justLoaded = true;
|
||||
|
||||
new Handler().postDelayed(() -> activity.runOnUiThread(() -> {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
BroadcastReceiver onComplete = new BroadcastReceiver() {
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (downloadingFile != null) {
|
||||
openFile(downloadingFile);
|
||||
downloadingFile = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
activity.registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
|
||||
|
||||
app.apiEdziennik.initMessagesWebView(webView, app, /*app.profile.messagesWebFullVersion*/false, false);
|
||||
webView.getSettings().setJavaScriptEnabled(true);
|
||||
webView.getSettings().setAllowFileAccess(true);
|
||||
webView.setDownloadListener((url, userAgent, contentDisposition, mimetype, contentLength) -> {
|
||||
String filename = getFileNameFromDisposition(contentDisposition);
|
||||
try {
|
||||
URL urlObj = new URL(url);
|
||||
Log.d(TAG, "Host "+urlObj.getProtocol()+"://"+urlObj.getHost());
|
||||
Log.d(TAG, "Cookies "+CookieManager.getInstance().getCookie(urlObj.getProtocol()+"://"+urlObj.getHost()));
|
||||
|
||||
downloadFile(getActivity(), url, filename, contentLength, CookieManager.getInstance().getCookie(urlObj.getProtocol()+"://"+urlObj.getHost()));
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Anim.fadeOut(progressBar, 400, null);
|
||||
});
|
||||
|
||||
webView.setWebViewClient(new WebViewClient() {
|
||||
boolean loadingFinished = true;
|
||||
boolean redirect = false;
|
||||
@Override
|
||||
public boolean shouldOverrideUrlLoading(WebView view, String request) {
|
||||
if (!loadingFinished) {
|
||||
redirect = true;
|
||||
}
|
||||
|
||||
loadingFinished = false;
|
||||
webView.loadUrl(request);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
||||
super.onPageStarted(view, url, favicon);
|
||||
MessagesWebFragment.this.error.setVisibility(View.GONE);
|
||||
loadingFinished = false;
|
||||
//SHOW LOADING IF IT ISNT ALREADY VISIBLE
|
||||
if (progressBar.getVisibility() != View.VISIBLE)
|
||||
Anim.fadeIn(progressBar, 400, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
if (!redirect) {
|
||||
loadingFinished = true;
|
||||
}
|
||||
|
||||
if (loadingFinished && !redirect) {
|
||||
//HIDE LOADING IT HAS FINISHED
|
||||
//String cookies = CookieManager.getInstance().getCookie(url);
|
||||
//Log.d(TAG, "All the cookies in a string:" + cookies);
|
||||
Anim.fadeOut(progressBar, 400, null);
|
||||
/*if (app.profile.messagesWebFullVersion && justLoaded && app.profile.loginType == Register.LOGIN_TYPE_MOBIDZIENNIK) {
|
||||
if (!webView.getUrl().contains("wiadomosci")) {
|
||||
// redirect to messages view
|
||||
webView.loadUrl("https://" + app.getLoginData("serverName", "") + ".mobidziennik.pl/mobile/wiadomosci");
|
||||
}
|
||||
justLoaded = false;
|
||||
}*/
|
||||
} else {
|
||||
redirect = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
|
||||
if (app == null || app.profile == null || activity == null || b == null || !isAdded())
|
||||
return;
|
||||
|
||||
MessagesWebFragment.this.error.setVisibility(View.VISIBLE);
|
||||
MessagesWebFragment.this.error.setText(getString(R.string.error_occured_format, error.toString()));
|
||||
super.onReceivedError(view, request, error);
|
||||
}
|
||||
});
|
||||
|
||||
if(Build.VERSION.SDK_INT >= 21) {
|
||||
webView.getSettings().setMixedContentMode(0);
|
||||
webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||
} else if(Build.VERSION.SDK_INT >= 19) {
|
||||
webView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||
} else {
|
||||
webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
|
||||
}
|
||||
|
||||
webView.setWebChromeClient(new WebChromeClient(){
|
||||
//For Android 5.0+
|
||||
public boolean onShowFileChooser(
|
||||
WebView webView, ValueCallback<Uri[]> filePathCallback,
|
||||
WebChromeClient.FileChooserParams fileChooserParams){
|
||||
if(fileCallback != null){
|
||||
fileCallback.onReceiveValue(null);
|
||||
}
|
||||
fileCallback = filePathCallback;
|
||||
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
if(takePictureIntent.resolveActivity(app.getPackageManager()) != null){
|
||||
File photoFile = null;
|
||||
try{
|
||||
photoFile = createImageFile();
|
||||
takePictureIntent.putExtra("PhotoPath", photoPath);
|
||||
}catch(IOException ex){
|
||||
Log.e(TAG, "Image file creation failed", ex);
|
||||
}
|
||||
if(photoFile != null){
|
||||
photoPath = "file:" + photoFile.getAbsolutePath();
|
||||
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photoFile));
|
||||
}else{
|
||||
takePictureIntent = null;
|
||||
}
|
||||
}
|
||||
Intent contentSelectionIntent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
contentSelectionIntent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
contentSelectionIntent.setType("*/*");
|
||||
Intent[] intentArray;
|
||||
if(takePictureIntent != null){
|
||||
intentArray = new Intent[]{takePictureIntent};
|
||||
}else{
|
||||
intentArray = new Intent[0];
|
||||
}
|
||||
|
||||
Intent chooserIntent = new Intent(Intent.ACTION_CHOOSER);
|
||||
chooserIntent.putExtra(Intent.EXTRA_INTENT, contentSelectionIntent);
|
||||
chooserIntent.putExtra(Intent.EXTRA_TITLE, R.string.choose_file);
|
||||
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentArray);
|
||||
startActivityForResult(chooserIntent, REQUEST_FILE_CHOOSER);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}), 200);
|
||||
}
|
||||
|
||||
/*public void loadVersion(boolean fullVersion) {
|
||||
if (app.profile.messagesWebFullVersion != fullVersion) {
|
||||
app.profile.messagesWebFullVersion = fullVersion;
|
||||
app.profile.savePending = true;
|
||||
justLoaded = true;
|
||||
app.apiEdziennik.initMessagesWebView(webView, app, fullVersion, true);
|
||||
}
|
||||
}*/
|
||||
|
||||
public void performReload() {
|
||||
webView.reload();
|
||||
}
|
||||
|
||||
public boolean processBackKey()
|
||||
{
|
||||
if (webView.canGoBack())
|
||||
{
|
||||
webView.goBack();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -50,6 +50,7 @@ import pl.szczodrzynski.edziennik.network.ServerRequest;
|
||||
import pl.szczodrzynski.edziennik.receivers.BootReceiver;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncWorker;
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog;
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.webpush.WebPushConfigActivity;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
@ -263,7 +264,7 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
.color(IconicsColor.colorInt(iconColor))
|
||||
)
|
||||
.setOnClickAction(() -> {
|
||||
app.apiEdziennik.guiRemoveProfile(activity, app.profile.getId(), app.profile.getName());
|
||||
new ProfileRemoveDialog(activity, app.profile.getId(), app.profile.getName());
|
||||
})
|
||||
);
|
||||
|
||||
@ -1291,8 +1292,6 @@ public class SettingsNewFragment extends MaterialAboutFragment {
|
||||
if (app.profile == null)
|
||||
return new MaterialAboutList.Builder().build();
|
||||
|
||||
//configurableEndpoints = Edziennik.getApi(app, app.profile.loginStoreType).getConfigurableEndpoints(app.profile);
|
||||
|
||||
MaterialAboutList materialAboutList = new MaterialAboutList();
|
||||
materialAboutList.addCard(getCardWithItems(null, getProfileCard(false)));
|
||||
materialAboutList.addCard(getCardWithItems(getString(R.string.settings_theme_title_text), getThemeCard(false)));
|
||||
|
@ -51,6 +51,7 @@ import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull;
|
||||
import pl.szczodrzynski.edziennik.databinding.FragmentTimetableBinding;
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorDialog;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment;
|
||||
import pl.szczodrzynski.edziennik.utils.SpannableHtmlTagHandler;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
@ -422,7 +423,7 @@ public class TimetableFragment extends Fragment {
|
||||
linearLayout = (LinearLayout) getLayoutInflater().inflate(R.layout.row_timetable_block_item, null);
|
||||
}
|
||||
catch (Exception e) {
|
||||
app.apiEdziennik.guiReportException(activity, 385, e);
|
||||
new ErrorDialog(activity, e);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
package pl.szczodrzynski.edziennik.ui.modules.timetable.v2
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentStatePagerAdapter
|
||||
import pl.szczodrzynski.edziennik.ui.modules.timetable.v2.day.TimetableDayFragment
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||
|
||||
@ -16,7 +18,11 @@ class TimetablePagerAdapter(val fragmentManager: FragmentManager, val items: Lis
|
||||
private val weekEnd by lazy { weekStart.clone().stepForward(0, 0, 6) }
|
||||
|
||||
override fun getItem(position: Int): Fragment {
|
||||
return pl.szczodrzynski.edziennik.ui.modules.timetable.v2.day.TimetableDayFragment(items[position])
|
||||
return TimetableDayFragment().apply {
|
||||
arguments = Bundle().apply {
|
||||
putInt("date", items[position].value)
|
||||
}
|
||||
}
|
||||
/*return TimetableDayFragment().apply {
|
||||
arguments = Bundle().also {
|
||||
it.putLong("date", items[position].value.toLong())
|
||||
|
@ -25,7 +25,7 @@ import pl.szczodrzynski.navlib.getColorFromAttr
|
||||
import java.util.*
|
||||
import kotlin.math.min
|
||||
|
||||
class TimetableDayFragment(val date: Date) : Fragment() {
|
||||
class TimetableDayFragment() : Fragment() {
|
||||
companion object {
|
||||
private const val TAG = "TimetableDayFragment"
|
||||
}
|
||||
@ -33,6 +33,7 @@ class TimetableDayFragment(val date: Date) : Fragment() {
|
||||
private lateinit var app: App
|
||||
private lateinit var activity: MainActivity
|
||||
private lateinit var b: FragmentTimetableV2DayBinding
|
||||
private lateinit var date: Date
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
activity = (getActivity() as MainActivity?) ?: return null
|
||||
@ -40,7 +41,7 @@ class TimetableDayFragment(val date: Date) : Fragment() {
|
||||
return null
|
||||
app = activity.application as App
|
||||
b = FragmentTimetableV2DayBinding.inflate(inflater)
|
||||
Log.d(TAG, "onCreateView, date=$date")
|
||||
date = arguments?.getInt("date")?.let { Date.fromValue(it) } ?: Date.getToday()
|
||||
return b.root
|
||||
}
|
||||
|
||||
|
@ -12,13 +12,11 @@ public class Date implements Comparable<Date> {
|
||||
public int month = 0;
|
||||
public int day = 0;
|
||||
|
||||
public Date()
|
||||
{
|
||||
public Date() {
|
||||
this(2000, 0, 0);
|
||||
}
|
||||
|
||||
public Date(int year, int month, int day)
|
||||
{
|
||||
public Date(int year, int month, int day) {
|
||||
this.year = year;
|
||||
this.month = month;
|
||||
this.day = day;
|
||||
@ -43,14 +41,8 @@ public class Date implements Comparable<Date> {
|
||||
return new Date(this.year, this.month, this.day);
|
||||
}
|
||||
|
||||
public long combineWith(Time time) {
|
||||
if (time == null) {
|
||||
return getInMillis();
|
||||
}
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.set(this.year, this.month-1, this.day, time.hour, time.minute, time.second);
|
||||
c.set(Calendar.MILLISECOND, 0);
|
||||
return c.getTimeInMillis();
|
||||
public static Date fromYmd(String dateTime) {
|
||||
return new Date(Integer.parseInt(dateTime.substring(0, 4)), Integer.parseInt(dateTime.substring(4, 6)), Integer.parseInt(dateTime.substring(6, 8)));
|
||||
}
|
||||
|
||||
public static Date fromMillis(long millis) {
|
||||
@ -67,9 +59,8 @@ public class Date implements Comparable<Date> {
|
||||
return Calendar.getInstance().getTimeInMillis();
|
||||
}
|
||||
|
||||
public int getWeekDay()
|
||||
{
|
||||
return Week.getWeekDayFromDate(this);
|
||||
public static Date fromY_m_d(String dateTime) {
|
||||
return new Date(Integer.parseInt(dateTime.substring(0, 4)), Integer.parseInt(dateTime.substring(5, 7)), Integer.parseInt(dateTime.substring(8, 10)));
|
||||
}
|
||||
|
||||
public long getInMillis() {
|
||||
@ -83,142 +74,167 @@ public class Date implements Comparable<Date> {
|
||||
return getInMillis() / 1000;
|
||||
}
|
||||
|
||||
public Date stepForward(int years, int months, int days)
|
||||
{
|
||||
public static Date fromd_m_Y(String dateTime) {
|
||||
return new Date(Integer.parseInt(dateTime.substring(6, 10)), Integer.parseInt(dateTime.substring(3, 5)), Integer.parseInt(dateTime.substring(0, 2)));
|
||||
}
|
||||
|
||||
public static long fromIso(String dateTime) {
|
||||
return Date.fromY_m_d(dateTime).combineWith(new Time(Integer.parseInt(dateTime.substring(11, 13)), Integer.parseInt(dateTime.substring(14, 16)), Integer.parseInt(dateTime.substring(17, 19))));
|
||||
}
|
||||
|
||||
public static long fromIsoHm(String dateTime) {
|
||||
return Date.fromY_m_d(dateTime).combineWith(new Time(Integer.parseInt(dateTime.substring(11, 13)), Integer.parseInt(dateTime.substring(14, 16)), 0));
|
||||
}
|
||||
|
||||
public static Date fromValue(int value) {
|
||||
int year = value / 10000;
|
||||
int month = (value - year * 10000) / 100;
|
||||
int day = (value - year * 10000 - month * 100);
|
||||
return new Date(year, month, day);
|
||||
}
|
||||
|
||||
public static Date getToday() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
return new Date(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH));
|
||||
}
|
||||
|
||||
public static int diffDays(Date d1, Date d2) {
|
||||
return (int) ((d1.getInMillis() - d2.getInMillis()) / (24 * 60 * 60 * 1000));
|
||||
}
|
||||
|
||||
public static boolean isToday(Date date) {
|
||||
return equals(date, getToday());
|
||||
}
|
||||
|
||||
public static boolean isToday(String dateStr) {
|
||||
return equals(dateStr, getToday());
|
||||
}
|
||||
|
||||
public static boolean equals(Date first, Date second) {
|
||||
return (first.getValue() == second.getValue());
|
||||
}
|
||||
|
||||
public static boolean equals(String first, Date second) {
|
||||
return equals(new Date().parseFromYmd(first), second);
|
||||
}
|
||||
|
||||
public long combineWith(Time time) {
|
||||
if (time == null) {
|
||||
return getInMillis();
|
||||
}
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.set(this.year, this.month - 1, this.day, time.hour, time.minute, time.second);
|
||||
c.set(Calendar.MILLISECOND, 0);
|
||||
return c.getTimeInMillis();
|
||||
}
|
||||
|
||||
public int getWeekDay() {
|
||||
return Week.getWeekDayFromDate(this);
|
||||
}
|
||||
|
||||
public Date stepForward(int years, int months, int days) {
|
||||
this.day += days;
|
||||
if (day > daysInMonth()) {
|
||||
day -= daysInMonth();
|
||||
month++;
|
||||
}
|
||||
this.month += months;
|
||||
if (month > 12) {
|
||||
month -= 12;
|
||||
year++;
|
||||
}
|
||||
this.year += years;
|
||||
/*Calendar c = Calendar.getInstance();
|
||||
int newMonth = month + months;
|
||||
if (newMonth > 12) {
|
||||
newMonth = 1;
|
||||
years++;
|
||||
}
|
||||
c.set(year+years, newMonth - 1, day);
|
||||
c.setTimeInMillis(c.getTimeInMillis() + days*24*60*60*1000);
|
||||
c.set(year + years, newMonth - 1, day);
|
||||
c.setTimeInMillis(c.getTimeInMillis() + days * 24 * 60 * 60 * 1000);
|
||||
this.year = c.get(Calendar.YEAR);
|
||||
this.month = c.get(Calendar.MONTH) + 1;
|
||||
this.day = c.get(Calendar.DAY_OF_MONTH);
|
||||
this.day = c.get(Calendar.DAY_OF_MONTH);*/
|
||||
return this;
|
||||
}
|
||||
|
||||
public Date parseFromYmd(String dateTime)
|
||||
{
|
||||
public Date parseFromYmd(String dateTime) {
|
||||
this.year = Integer.parseInt(dateTime.substring(0, 4));
|
||||
this.month = Integer.parseInt(dateTime.substring(4, 6));
|
||||
this.day = Integer.parseInt(dateTime.substring(6, 8));
|
||||
return this;
|
||||
}
|
||||
|
||||
public static Date fromYmd(String dateTime)
|
||||
{
|
||||
return new Date(Integer.parseInt(dateTime.substring(0, 4)), Integer.parseInt(dateTime.substring(4, 6)), Integer.parseInt(dateTime.substring(6, 8)));
|
||||
}
|
||||
|
||||
public static Date fromY_m_d(String dateTime)
|
||||
{
|
||||
return new Date(Integer.parseInt(dateTime.substring(0, 4)), Integer.parseInt(dateTime.substring(5, 7)), Integer.parseInt(dateTime.substring(8, 10)));
|
||||
}
|
||||
|
||||
public static long fromIso(String dateTime)
|
||||
{
|
||||
return Date.fromY_m_d(dateTime).combineWith(new Time(Integer.parseInt(dateTime.substring(11, 13)), Integer.parseInt(dateTime.substring(14, 16)), Integer.parseInt(dateTime.substring(17, 19))));
|
||||
}
|
||||
|
||||
public static long fromIsoHm(String dateTime)
|
||||
{
|
||||
return Date.fromY_m_d(dateTime).combineWith(new Time(Integer.parseInt(dateTime.substring(11, 13)), Integer.parseInt(dateTime.substring(14, 16)), 0));
|
||||
}
|
||||
|
||||
public int getValue()
|
||||
{
|
||||
public int getValue() {
|
||||
return year * 10000 + month * 100 + day;
|
||||
}
|
||||
|
||||
public static Date fromValue(int value) {
|
||||
int year = value / 10000;
|
||||
int month = (value-year*10000) / 100;
|
||||
int day = (value-year*10000-month*100);
|
||||
return new Date(year, month, day);
|
||||
}
|
||||
|
||||
public String getStringValue()
|
||||
{
|
||||
public String getStringValue() {
|
||||
return Integer.toString(getValue());
|
||||
}
|
||||
|
||||
public String getStringYmd()
|
||||
{
|
||||
return year +(month < 10 ? "0" : "")+ month +(day < 10 ? "0" : "")+ day;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 2019-06-02
|
||||
*/
|
||||
public String getStringY_m_d()
|
||||
{
|
||||
return year +(month < 10 ? "-0" : "-")+ month +(day < 10 ? "-0" : "-")+ day;
|
||||
}
|
||||
public String getStringDm()
|
||||
{
|
||||
return day +"."+(month < 10 ? "0" : "")+ month;
|
||||
}
|
||||
public String getStringDmy()
|
||||
{
|
||||
return day +"."+(month < 10 ? "0" : "")+ month +"."+ year;
|
||||
}
|
||||
|
||||
public String getFormattedString()
|
||||
{
|
||||
java.util.Date date = new java.util.Date();
|
||||
date.setTime(getInMillis());
|
||||
DateFormat format = DateFormat.getDateInstance(DateFormat.LONG, Locale.getDefault());
|
||||
if (year == Date.getToday().year) {
|
||||
return format.format(date).replace(", "+year, "").replace(" "+year, "");
|
||||
}
|
||||
else {
|
||||
return format.format(date);
|
||||
}
|
||||
}
|
||||
public String getFormattedStringShort()
|
||||
{
|
||||
java.util.Date date = new java.util.Date();
|
||||
date.setTime(getInMillis());
|
||||
DateFormat format = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault());
|
||||
if (year == Date.getToday().year) {
|
||||
return format.format(date).replace(", "+year, "").replace(" "+year, "");
|
||||
}
|
||||
else {
|
||||
return format.format(date);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isLeap() {
|
||||
return ((year & 3) == 0) && ((year % 100) != 0 || (year % 400) == 0);
|
||||
}
|
||||
|
||||
public static Date getToday()
|
||||
{
|
||||
Calendar cal = Calendar.getInstance();
|
||||
return new Date(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH)+1, cal.get(Calendar.DAY_OF_MONTH));
|
||||
public int daysInMonth() {
|
||||
switch (month) {
|
||||
case 1:
|
||||
case 3:
|
||||
case 5:
|
||||
case 7:
|
||||
case 8:
|
||||
case 10:
|
||||
case 12:
|
||||
return 31;
|
||||
case 2: return isLeap() ? 29 : 28;
|
||||
case 4:
|
||||
case 6:
|
||||
case 9:
|
||||
case 11:
|
||||
return 30;
|
||||
}
|
||||
return 31;
|
||||
}
|
||||
|
||||
public static int diffDays(Date d1, Date d2) {
|
||||
return (int)((d1.getInMillis() - d2.getInMillis()) / (24*60*60*1000));
|
||||
public String getStringYmd() {
|
||||
return year + (month < 10 ? "0" : "") + month + (day < 10 ? "0" : "") + day;
|
||||
}
|
||||
|
||||
public static boolean isToday(Date date)
|
||||
{
|
||||
return equals(date, getToday());
|
||||
/**
|
||||
* @return 2019-06-02
|
||||
*/
|
||||
public String getStringY_m_d() {
|
||||
return year + (month < 10 ? "-0" : "-") + month + (day < 10 ? "-0" : "-") + day;
|
||||
}
|
||||
public static boolean isToday(String dateStr)
|
||||
{
|
||||
return equals(dateStr, getToday());
|
||||
|
||||
public String getStringDm() {
|
||||
return day + "." + (month < 10 ? "0" : "") + month;
|
||||
}
|
||||
public static boolean equals(Date first, Date second)
|
||||
{
|
||||
return (first.getValue() == second.getValue());
|
||||
|
||||
public String getStringDmy() {
|
||||
return day + "." + (month < 10 ? "0" : "") + month + "." + year;
|
||||
}
|
||||
public static boolean equals(String first, Date second)
|
||||
{
|
||||
return equals(new Date().parseFromYmd(first), second);
|
||||
|
||||
public String getFormattedString() {
|
||||
java.util.Date date = new java.util.Date();
|
||||
date.setTime(getInMillis());
|
||||
DateFormat format = DateFormat.getDateInstance(DateFormat.LONG, Locale.getDefault());
|
||||
if (year == Date.getToday().year) {
|
||||
return format.format(date).replace(", " + year, "").replace(" " + year, "");
|
||||
} else {
|
||||
return format.format(date);
|
||||
}
|
||||
}
|
||||
|
||||
public String getFormattedStringShort() {
|
||||
java.util.Date date = new java.util.Date();
|
||||
date.setTime(getInMillis());
|
||||
DateFormat format = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault());
|
||||
if (year == Date.getToday().year) {
|
||||
return format.format(date).replace(", " + year, "").replace(" " + year, "");
|
||||
} else {
|
||||
return format.format(date);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -9,6 +9,7 @@ public class ItemWidgetTimetableModel {
|
||||
public String separatorProfileName = null;
|
||||
|
||||
public int profileId;
|
||||
public long lessonId;
|
||||
public Date lessonDate;
|
||||
public Time startTime;
|
||||
public Time endTime;
|
||||
|
@ -1,10 +1,11 @@
|
||||
package pl.szczodrzynski.edziennik.utils.models;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
public class Time {
|
||||
public class Time implements Comparable<Time> {
|
||||
public int hour = 0;
|
||||
public int minute = 0;
|
||||
public int second = 0;
|
||||
@ -175,6 +176,11 @@ public class Time {
|
||||
return (currentTime.getValue() >= startTime.getValue() && currentTime.getValue() <= endTime.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NonNull Time o) {
|
||||
return this.getValue() - o.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
return obj instanceof Time && this.getValue() == ((Time) obj).getValue();
|
||||
|
@ -21,8 +21,8 @@ import java.util.List;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.WidgetTimetable;
|
||||
import pl.szczodrzynski.edziennik.databinding.DialogWidgetConfigBinding;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile;
|
||||
import pl.szczodrzynski.edziennik.databinding.DialogWidgetConfigBinding;
|
||||
import pl.szczodrzynski.edziennik.widgets.luckynumber.WidgetLuckyNumber;
|
||||
import pl.szczodrzynski.edziennik.widgets.notifications.WidgetNotifications;
|
||||
|
||||
@ -78,7 +78,7 @@ public class WidgetConfigActivity extends Activity {
|
||||
|
||||
AsyncTask.execute(() -> {
|
||||
profileList = app.db.profileDao().getAllNow();
|
||||
filterOutArchived(profileList);
|
||||
profileList = filterOutArchived(profileList);
|
||||
|
||||
if (widgetType == WIDGET_NOTIFICATIONS)
|
||||
this.runOnUiThread(this::configure);
|
||||
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-14.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.widgets.timetable
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import kotlinx.coroutines.*
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.timetable.LessonDetailsDialog
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class LessonDialogActivity : AppCompatActivity(), CoroutineScope {
|
||||
companion object {
|
||||
private const val TAG = "LessonDialogActivity"
|
||||
}
|
||||
|
||||
private lateinit var job: Job
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
|
||||
private val shownDialogs = hashSetOf<String>()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
window.setBackgroundDrawable(ColorDrawable(0))
|
||||
|
||||
job = Job()
|
||||
|
||||
setTheme(Themes.appThemeNoDisplay)
|
||||
|
||||
val app = application as App
|
||||
launch {
|
||||
val deferred = async(Dispatchers.Default) {
|
||||
val extras = intent?.extras
|
||||
|
||||
val profileId = extras?.getInt("profileId") ?: return@async null
|
||||
|
||||
if (extras.getBoolean("separatorItem", false)) {
|
||||
val i = Intent(app, MainActivity::class.java)
|
||||
.putExtra("fragmentId", MainActivity.DRAWER_ITEM_TIMETABLE)
|
||||
.putExtra("profileId", profileId)
|
||||
.addFlags(FLAG_ACTIVITY_REORDER_TO_FRONT)
|
||||
app.startActivity(i)
|
||||
finish()
|
||||
return@async null
|
||||
}
|
||||
|
||||
val lessonId = extras.getLong("lessonId")
|
||||
|
||||
app.db.timetableDao().getByIdNow(profileId, lessonId)
|
||||
}
|
||||
val lesson = deferred.await()
|
||||
lesson?.let {
|
||||
LessonDetailsDialog(
|
||||
this@LessonDialogActivity,
|
||||
lesson,
|
||||
onShowListener = { tag ->
|
||||
shownDialogs.add(tag)
|
||||
},
|
||||
onDismissListener = { tag ->
|
||||
shownDialogs.remove(tag)
|
||||
if (shownDialogs.isEmpty())
|
||||
finish()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -12,13 +12,14 @@ import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import android.text.Html;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
import android.widget.RemoteViewsService;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
|
||||
import com.mikepenz.iconics.IconicsColor;
|
||||
import com.mikepenz.iconics.IconicsDrawable;
|
||||
import com.mikepenz.iconics.IconicsSize;
|
||||
@ -62,7 +63,7 @@ public class WidgetTimetableListProvider implements RemoteViewsService.RemoteVie
|
||||
public void onDataSetChanged() {
|
||||
// executed EVERY TIME
|
||||
Log.d(TAG, "onDataSetChanged for appWidgetId: "+appWidgetId);
|
||||
lessons = WidgetTimetable.timetables == null ? null : WidgetTimetable.timetables.get(appWidgetId);
|
||||
lessons = WidgetTimetable.Companion.getTimetables() == null ? null : WidgetTimetable.Companion.getTimetables().get(appWidgetId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -163,9 +164,13 @@ public class WidgetTimetableListProvider implements RemoteViewsService.RemoteVie
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra("profileId", lesson.profileId);
|
||||
intent.putExtra("date", lesson.lessonDate.getStringValue());
|
||||
intent.putExtra("startTime", lesson.startTime.getStringValue());
|
||||
intent.putExtra("endTime", lesson.endTime.getStringValue());
|
||||
intent.putExtra("lessonId", lesson.lessonId);
|
||||
if (lesson.lessonDate != null)
|
||||
intent.putExtra("date", lesson.lessonDate.getStringValue());
|
||||
if (lesson.startTime != null)
|
||||
intent.putExtra("startTime", lesson.startTime.getStringValue());
|
||||
if (lesson.endTime != null)
|
||||
intent.putExtra("endTime", lesson.endTime.getStringValue());
|
||||
views.setOnClickFillInIntent(R.id.widgetTimetableRoot, intent);
|
||||
|
||||
views.setTextViewText(R.id.widgetTimetableTime, lesson.startTime.getStringHM() + " - " + lesson.endTime.getStringHM());
|
||||
@ -239,30 +244,18 @@ public class WidgetTimetableListProvider implements RemoteViewsService.RemoteVie
|
||||
}
|
||||
}
|
||||
}
|
||||
//views.setViewVisibility(R.id.widgetTimetableEvent1, View.VISIBLE);
|
||||
//views.setBitmap(R.id.widgetTimetableEvent1, "setImageBitmap", getColoredBitmap(context, R.drawable.event_color_circle, 0xff4caf50, eventIndicatorSize, eventIndicatorSize));
|
||||
|
||||
if (lesson.subjectName == null) {
|
||||
lesson.subjectName = context.getString(R.string.timetable_no_subject_name);
|
||||
}
|
||||
if (lesson.classroomName == null) {
|
||||
lesson.classroomName = context.getString(R.string.timetable_no_classroom);
|
||||
}
|
||||
|
||||
views.setViewVisibility(R.id.widgetTimetableOldSubjectName, View.GONE);
|
||||
if (lesson.lessonChange) {
|
||||
if (lesson.newSubjectName == null) {
|
||||
views.setTextViewText(R.id.widgetTimetableSubjectName, Html.fromHtml("<i>"+lesson.subjectName+"</i>"));
|
||||
}
|
||||
else {
|
||||
views.setViewVisibility(R.id.widgetTimetableOldSubjectName, View.VISIBLE);
|
||||
views.setTextViewText(R.id.widgetTimetableOldSubjectName, Html.fromHtml("<del>"+lesson.subjectName+"</del>"));
|
||||
views.setTextViewText(R.id.widgetTimetableSubjectName, lesson.newSubjectName);
|
||||
}
|
||||
|
||||
if (lesson.newClassroomName == null) {
|
||||
if (lesson.classroomName == null || lesson.classroomName.equals("")) {
|
||||
lesson.classroomName = context.getString(R.string.timetable_no_classroom);
|
||||
}
|
||||
views.setTextViewText(R.id.widgetTimetableClassroomName, lesson.classroomName);
|
||||
}
|
||||
else {
|
||||
views.setTextViewText(R.id.widgetTimetableClassroomName, Html.fromHtml("<i>"+lesson.newClassroomName+"</i>"));
|
||||
}
|
||||
|
||||
views.setTextViewText(R.id.widgetTimetableSubjectName, Html.fromHtml("<i>"+lesson.subjectName+"</i>"));
|
||||
views.setTextViewText(R.id.widgetTimetableClassroomName, Html.fromHtml("<i>"+lesson.classroomName+"</i>"));
|
||||
}
|
||||
else if (lesson.lessonCancelled) {
|
||||
views.setTextViewText(R.id.widgetTimetableSubjectName, Html.fromHtml("<del>"+lesson.subjectName+"</del>"));
|
||||
@ -272,7 +265,6 @@ public class WidgetTimetableListProvider implements RemoteViewsService.RemoteVie
|
||||
views.setTextViewText(R.id.widgetTimetableSubjectName, lesson.subjectName);
|
||||
views.setTextViewText(R.id.widgetTimetableClassroomName, lesson.classroomName);
|
||||
}
|
||||
|
||||
}
|
||||
else if (!triedToReload) {
|
||||
// try to reload the widget
|
||||
|
@ -8,16 +8,17 @@
|
||||
android:orientation="vertical"
|
||||
android:visibility="visible">
|
||||
|
||||
<LinearLayout
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="32dp" />
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/coordinator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:visibility="visible">
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="32dp" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/nav_host_fragment"
|
||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||
@ -30,7 +31,7 @@
|
||||
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:navGraph="@navigation/nav_login" />
|
||||
</LinearLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
<!--<io.codetail.widget.RevealFrameLayout
|
||||
android:layout_width="match_parent"
|
||||
|
@ -526,7 +526,7 @@
|
||||
<string name="profile_menu_open_settings">Settings</string>
|
||||
<string name="profile_menu_remove">Remove profile</string>
|
||||
<string name="profile_menu_remove_confirm">Are you sure?</string>
|
||||
<string name="profile_menu_remove_confirm_text_format">You are trying to remove profile %s. This means removing this profile\'s data (grades, timetables, events…) from the app.\n\nYou\'ll be able to restore most of the data by logging in again.\n\nDo you really want to remove profile %s?</string>
|
||||
<string name="profile_menu_remove_confirm_text_format">You are trying to remove profile <b>%s</b>. This means removing this profile\'s data (grades, timetables, events…) from the app.\n\nYou\'ll be able to restore most of the data by logging in again.\n\nDo you really want to remove profile %s?</string>
|
||||
<string name="rate_snackbar_negative">Never</string>
|
||||
<string name="rate_snackbar_neutral">Later</string>
|
||||
<string name="rate_snackbar_positive">Rate now</string>
|
||||
|
276
app/src/main/res/values/errors.xml
Normal file
276
app/src/main/res/values/errors.xml
Normal file
@ -0,0 +1,276 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) Kuba Szczodrzyński 2019-11-13.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="error_50" translatable="false">ERROR_REQUEST_FAILURE</string>
|
||||
<string name="error_51" translatable="false">ERROR_REQUEST_HTTP_400</string>
|
||||
<string name="error_52" translatable="false">ERROR_REQUEST_HTTP_401</string>
|
||||
<string name="error_53" translatable="false">ERROR_REQUEST_HTTP_403</string>
|
||||
<string name="error_54" translatable="false">ERROR_REQUEST_HTTP_404</string>
|
||||
<string name="error_55" translatable="false">ERROR_REQUEST_HTTP_405</string>
|
||||
<string name="error_56" translatable="false">ERROR_REQUEST_HTTP_410</string>
|
||||
<string name="error_57" translatable="false">ERROR_REQUEST_HTTP_500</string>
|
||||
<string name="error_100" translatable="false">ERROR_RESPONSE_EMPTY</string>
|
||||
<string name="error_101" translatable="false">ERROR_LOGIN_DATA_MISSING</string>
|
||||
<string name="error_102" translatable="false">ERROR_LOGIN_DATA_INVALID</string>
|
||||
<string name="error_105" translatable="false">ERROR_PROFILE_MISSING</string>
|
||||
<string name="error_110" translatable="false">ERROR_INVALID_LOGIN_MODE</string>
|
||||
<string name="error_111" translatable="false">ERROR_LOGIN_METHOD_NOT_SATISFIED</string>
|
||||
<string name="error_112" translatable="false">ERROR_NOT_IMPLEMENTED</string>
|
||||
|
||||
<string name="error_115" translatable="false">ERROR_NO_STUDENTS_IN_ACCOUNT</string>
|
||||
|
||||
<string name="error_120" translatable="false">CODE_INTERNAL_LIBRUS_ACCOUNT_410</string>
|
||||
<string name="error_121" translatable="false">CODE_INTERNAL_LIBRUS_SYNERGIA_EXPIRED</string>
|
||||
<string name="error_124" translatable="false">ERROR_LOGIN_LIBRUS_API_CAPTCHA_NEEDED</string>
|
||||
<string name="error_125" translatable="false">ERROR_LOGIN_LIBRUS_API_CONNECTION_PROBLEMS</string>
|
||||
<string name="error_126" translatable="false">ERROR_LOGIN_LIBRUS_API_INVALID_CLIENT</string>
|
||||
<string name="error_127" translatable="false">ERROR_LOGIN_LIBRUS_API_REG_ACCEPT_NEEDED</string>
|
||||
<string name="error_128" translatable="false">ERROR_LOGIN_LIBRUS_API_CHANGE_PASSWORD_ERROR</string>
|
||||
<string name="error_129" translatable="false">ERROR_LOGIN_LIBRUS_API_PASSWORD_CHANGE_REQUIRED</string>
|
||||
<string name="error_130" translatable="false">ERROR_LOGIN_LIBRUS_API_INVALID_LOGIN</string>
|
||||
<string name="error_131" translatable="false">ERROR_LOGIN_LIBRUS_API_OTHER</string>
|
||||
<string name="error_132" translatable="false">ERROR_LOGIN_LIBRUS_PORTAL_CSRF_MISSING</string>
|
||||
<string name="error_133" translatable="false">ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED</string>
|
||||
<string name="error_134" translatable="false">ERROR_LOGIN_LIBRUS_PORTAL_ACTION_ERROR</string>
|
||||
<string name="error_139" translatable="false">ERROR_LOGIN_LIBRUS_PORTAL_SYNERGIA_TOKEN_MISSING</string>
|
||||
<string name="error_140" translatable="false">ERROR_LIBRUS_API_TOKEN_EXPIRED</string>
|
||||
<string name="error_141" translatable="false">ERROR_LIBRUS_API_INSUFFICIENT_SCOPES</string>
|
||||
<string name="error_142" translatable="false">ERROR_LIBRUS_API_OTHER</string>
|
||||
<string name="error_143" translatable="false">ERROR_LIBRUS_API_ACCESS_DENIED</string>
|
||||
<string name="error_144" translatable="false">ERROR_LIBRUS_API_RESOURCE_NOT_FOUND</string>
|
||||
<string name="error_145" translatable="false">ERROR_LIBRUS_API_DATA_NOT_FOUND</string>
|
||||
<string name="error_146" translatable="false">ERROR_LIBRUS_API_TIMETABLE_NOT_PUBLIC</string>
|
||||
<string name="error_147" translatable="false">ERROR_LIBRUS_API_RESOURCE_ACCESS_DENIED</string>
|
||||
<string name="error_148" translatable="false">ERROR_LIBRUS_API_INVALID_REQUEST_PARAMS</string>
|
||||
<string name="error_149" translatable="false">ERROR_LIBRUS_API_INCORRECT_ENDPOINT</string>
|
||||
<string name="error_150" translatable="false">ERROR_LIBRUS_API_LUCKY_NUMBER_NOT_ACTIVE</string>
|
||||
<string name="error_151" translatable="false">ERROR_LIBRUS_API_NOTES_NOT_ACTIVE</string>
|
||||
<string name="error_152" translatable="false">ERROR_LOGIN_LIBRUS_SYNERGIA_NO_TOKEN</string>
|
||||
<string name="error_153" translatable="false">ERROR_LOGIN_LIBRUS_SYNERGIA_TOKEN_INVALID</string>
|
||||
<string name="error_154" translatable="false">ERROR_LOGIN_LIBRUS_SYNERGIA_NO_SESSION_ID</string>
|
||||
<string name="error_155" translatable="false">ERROR_LIBRUS_MESSAGES_ACCESS_DENIED</string>
|
||||
<string name="error_156" translatable="false">ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED</string>
|
||||
<string name="error_157" translatable="false">ERROR_LOGIN_LIBRUS_MESSAGES_NO_SESSION_ID</string>
|
||||
<string name="error_158" translatable="false">ERROR_LIBRUS_PORTAL_ACCESS_DENIED</string>
|
||||
<string name="error_159" translatable="false">ERROR_LIBRUS_PORTAL_API_DISABLED</string>
|
||||
<string name="error_160" translatable="false">ERROR_LIBRUS_PORTAL_SYNERGIA_DISCONNECTED</string>
|
||||
<string name="error_161" translatable="false">ERROR_LIBRUS_PORTAL_OTHER</string>
|
||||
<string name="error_162" translatable="false">ERROR_LIBRUS_PORTAL_SYNERGIA_NOT_FOUND</string>
|
||||
<string name="error_163" translatable="false">ERROR_LOGIN_LIBRUS_PORTAL_OTHER</string>
|
||||
<string name="error_164" translatable="false">ERROR_LOGIN_LIBRUS_PORTAL_CODE_EXPIRED</string>
|
||||
<string name="error_165" translatable="false">ERROR_LOGIN_LIBRUS_PORTAL_CODE_REVOKED</string>
|
||||
<string name="error_166" translatable="false">ERROR_LOGIN_LIBRUS_PORTAL_NO_CLIENT_ID</string>
|
||||
<string name="error_167" translatable="false">ERROR_LOGIN_LIBRUS_PORTAL_NO_CODE</string>
|
||||
<string name="error_168" translatable="false">ERROR_LOGIN_LIBRUS_PORTAL_NO_REFRESH</string>
|
||||
<string name="error_169" translatable="false">ERROR_LOGIN_LIBRUS_PORTAL_NO_REDIRECT</string>
|
||||
<string name="error_170" translatable="false">ERROR_LOGIN_LIBRUS_PORTAL_UNSUPPORTED_GRANT</string>
|
||||
<string name="error_171" translatable="false">ERROR_LOGIN_LIBRUS_PORTAL_INVALID_CLIENT_ID</string>
|
||||
<string name="error_172" translatable="false">ERROR_LOGIN_LIBRUS_PORTAL_REFRESH_INVALID</string>
|
||||
<string name="error_173" translatable="false">ERROR_LOGIN_LIBRUS_PORTAL_REFRESH_REVOKED</string>
|
||||
<string name="error_174" translatable="false">ERROR_LIBRUS_SYNERGIA_OTHER</string>
|
||||
<string name="error_175" translatable="false">ERROR_LIBRUS_SYNERGIA_MAINTENANCE</string>
|
||||
|
||||
<string name="error_201" translatable="false">ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_LOGIN</string>
|
||||
<string name="error_202" translatable="false">ERROR_LOGIN_MOBIDZIENNIK_WEB_OLD_PASSWORD</string>
|
||||
<string name="error_203" translatable="false">ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_DEVICE</string>
|
||||
<string name="error_204" translatable="false">ERROR_LOGIN_MOBIDZIENNIK_WEB_ARCHIVED</string>
|
||||
<string name="error_205" translatable="false">ERROR_LOGIN_MOBIDZIENNIK_WEB_MAINTENANCE</string>
|
||||
<string name="error_206" translatable="false">ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_ADDRESS</string>
|
||||
<string name="error_210" translatable="false">ERROR_LOGIN_MOBIDZIENNIK_WEB_OTHER</string>
|
||||
<string name="error_211" translatable="false">ERROR_MOBIDZIENNIK_WEB_ACCESS_DENIED</string>
|
||||
<string name="error_212" translatable="false">ERROR_MOBIDZIENNIK_WEB_NO_SESSION_KEY</string>
|
||||
<string name="error_216" translatable="false">ERROR_MOBIDZIENNIK_WEB_NO_SESSION_VALUE</string>
|
||||
<string name="error_213" translatable="false">ERROR_MOBIDZIENNIK_WEB_NO_SERVER_ID</string>
|
||||
<string name="error_214" translatable="false">ERROR_MOBIDZIENNIK_WEB_INVALID_RESPONSE</string>
|
||||
<string name="error_215" translatable="false">ERROR_LOGIN_MOBIDZIENNIK_WEB_NO_SESSION_ID</string>
|
||||
|
||||
<string name="error_301" translatable="false">ERROR_LOGIN_VULCAN_INVALID_SYMBOL</string>
|
||||
<string name="error_302" translatable="false">ERROR_LOGIN_VULCAN_INVALID_TOKEN</string>
|
||||
<string name="error_309" translatable="false">ERROR_LOGIN_VULCAN_INVALID_PIN</string>
|
||||
<string name="error_310" translatable="false">ERROR_LOGIN_VULCAN_INVALID_PIN_0_REMAINING</string>
|
||||
<string name="error_311" translatable="false">ERROR_LOGIN_VULCAN_INVALID_PIN_1_REMAINING</string>
|
||||
<string name="error_312" translatable="false">ERROR_LOGIN_VULCAN_INVALID_PIN_2_REMAINING</string>
|
||||
<string name="error_321" translatable="false">ERROR_LOGIN_VULCAN_EXPIRED_TOKEN</string>
|
||||
<string name="error_322" translatable="false">ERROR_LOGIN_VULCAN_OTHER</string>
|
||||
<string name="error_330" translatable="false">ERROR_LOGIN_VULCAN_ONLY_KINDERGARTEN</string>
|
||||
<string name="error_331" translatable="false">ERROR_LOGIN_VULCAN_NO_PUPILS</string>
|
||||
<string name="error_340" translatable="false">ERROR_VULCAN_API_MAINTENANCE</string>
|
||||
<string name="error_341" translatable="false">ERROR_VULCAN_API_BAD_REQUEST</string>
|
||||
<string name="error_342" translatable="false">ERROR_VULCAN_API_OTHER</string>
|
||||
|
||||
<string name="error_401" translatable="false">ERROR_LOGIN_IDZIENNIK_WEB_INVALID_LOGIN</string>
|
||||
<string name="error_402" translatable="false">ERROR_LOGIN_IDZIENNIK_WEB_INVALID_SCHOOL_NAME</string>
|
||||
<string name="error_403" translatable="false">ERROR_LOGIN_IDZIENNIK_WEB_PASSWORD_CHANGE_NEEDED</string>
|
||||
<string name="error_404" translatable="false">ERROR_LOGIN_IDZIENNIK_WEB_MAINTENANCE</string>
|
||||
<string name="error_405" translatable="false">ERROR_LOGIN_IDZIENNIK_WEB_SERVER_ERROR</string>
|
||||
<string name="error_410" translatable="false">ERROR_LOGIN_IDZIENNIK_WEB_OTHER</string>
|
||||
<string name="error_411" translatable="false">ERROR_LOGIN_IDZIENNIK_WEB_API_NO_ACCESS</string>
|
||||
<string name="error_420" translatable="false">ERROR_LOGIN_IDZIENNIK_WEB_NO_SESSION</string>
|
||||
<string name="error_421" translatable="false">ERROR_LOGIN_IDZIENNIK_WEB_NO_AUTH</string>
|
||||
<string name="error_422" translatable="false">ERROR_LOGIN_IDZIENNIK_WEB_NO_BEARER</string>
|
||||
<string name="error_430" translatable="false">ERROR_IDZIENNIK_WEB_ACCESS_DENIED</string>
|
||||
<string name="error_431" translatable="false">ERROR_IDZIENNIK_WEB_OTHER</string>
|
||||
<string name="error_432" translatable="false">ERROR_IDZIENNIK_WEB_MAINTENANCE</string>
|
||||
<string name="error_433" translatable="false">ERROR_IDZIENNIK_WEB_SERVER_ERROR</string>
|
||||
<string name="error_434" translatable="false">ERROR_IDZIENNIK_WEB_PASSWORD_CHANGE_NEEDED</string>
|
||||
<string name="error_440" translatable="false">ERROR_LOGIN_IDZIENNIK_FIRST_NO_SCHOOL_YEAR</string>
|
||||
<string name="error_441" translatable="false">ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA</string>
|
||||
<string name="error_450" translatable="false">ERROR_IDZIENNIK_API_ACCESS_DENIED</string>
|
||||
<string name="error_451" translatable="false">ERROR_IDZIENNIK_API_OTHER</string>
|
||||
|
||||
<string name="error_801" translatable="false">ERROR_TEMPLATE_WEB_OTHER</string>
|
||||
|
||||
<string name="error_900" translatable="false">EXCEPTION_API_TASK</string>
|
||||
<string name="error_901" translatable="false">EXCEPTION_LOGIN_LIBRUS_API_TOKEN</string>
|
||||
<string name="error_902" translatable="false">EXCEPTION_LOGIN_LIBRUS_PORTAL_TOKEN</string>
|
||||
<string name="error_903" translatable="false">EXCEPTION_LIBRUS_PORTAL_SYNERGIA_TOKEN</string>
|
||||
<string name="error_904" translatable="false">EXCEPTION_LIBRUS_API_REQUEST</string>
|
||||
<string name="error_905" translatable="false">EXCEPTION_LIBRUS_SYNERGIA_REQUEST</string>
|
||||
<string name="error_906" translatable="false">EXCEPTION_MOBIDZIENNIK_WEB_REQUEST</string>
|
||||
<string name="error_907" translatable="false">EXCEPTION_VULCAN_API_REQUEST</string>
|
||||
<string name="error_910" translatable="false">EXCEPTION_NOTIFY_AND_SYNC</string>
|
||||
<string name="error_911" translatable="false">EXCEPTION_LIBRUS_MESSAGES_REQUEST</string>
|
||||
<string name="error_912" translatable="false">EXCEPTION_IDZIENNIK_WEB_REQUEST</string>
|
||||
<string name="error_913" translatable="false">EXCEPTION_IDZIENNIK_WEB_API_REQUEST</string>
|
||||
<string name="error_914" translatable="false">EXCEPTION_IDZIENNIK_API_REQUEST</string>
|
||||
|
||||
<string name="error_1201" translatable="false">LOGIN_NO_ARGUMENTS</string>
|
||||
|
||||
<string name="error_50_reason">Błąd odpowiedzi serwera</string>
|
||||
<string name="error_51_reason">Błąd serwera: nieprawidłowe zapytanie</string>
|
||||
<string name="error_52_reason">Błąd serwera: odmowa dostępu</string>
|
||||
<string name="error_53_reason">Błąd serwera: dostęp zabroniony</string>
|
||||
<string name="error_54_reason">Błąd serwera: plik nie znaleziony</string>
|
||||
<string name="error_55_reason">Błąd serwera: nieprawidłowa metoda zapytania</string>
|
||||
<string name="error_56_reason">Błąd serwera: odpowiedź niedostępna</string>
|
||||
<string name="error_57_reason">Wewnętrzny błąd serwera</string>
|
||||
<string name="error_100_reason">Brak odpowiedzi serwera</string>
|
||||
<string name="error_101_reason">Dane logowania niekompletne</string>
|
||||
<string name="error_102_reason">Nieprawidłowe dane logowania</string>
|
||||
<string name="error_105_reason">Profil nie został ustawiony</string>
|
||||
<string name="error_110_reason">Nieprawidłowy sposób logowania</string>
|
||||
<string name="error_111_reason">Nie można wywołać metody logowania</string>
|
||||
<string name="error_112_reason">Nie zaimplementowano</string>
|
||||
|
||||
<string name="error_115_reason">Brak uczniów przypisanych do konta</string>
|
||||
|
||||
<string name="error_120_reason">CODE_INTERNAL_LIBRUS_ACCOUNT_410</string>
|
||||
<string name="error_121_reason">CODE_INTERNAL_LIBRUS_SYNERGIA_EXPIRED</string>
|
||||
<string name="error_124_reason">Wymagane wypełnienie CAPTCHA</string>
|
||||
<string name="error_125_reason">Problem z połączeniem</string>
|
||||
<string name="error_126_reason">Nieprawidłowy identyfikator klienta</string>
|
||||
<string name="error_127_reason">Wymagana akceptacja regulaminu</string>
|
||||
<string name="error_128_reason">Błąd zmiany hasła</string>
|
||||
<string name="error_129_reason">Wymagana zmiana hasła</string>
|
||||
<string name="error_130_reason">Nieprawidłowe dane logowania</string>
|
||||
<string name="error_131_reason">Inny błąd logowania do API</string>
|
||||
<string name="error_132_reason">Brak tokenu CSRF</string>
|
||||
<string name="error_133_reason">Konto LIBRUS nie zostało aktywowane</string>
|
||||
<string name="error_134_reason">Inny błąd logowania do Portalu LIBRUS</string>
|
||||
<string name="error_139_reason">Nie znaleziono tokenu Synergia</string>
|
||||
<string name="error_140_reason">Token API wygasł</string>
|
||||
<string name="error_141_reason">Niewystarczające uprawnienia</string>
|
||||
<string name="error_142_reason">Inny błąd API</string>
|
||||
<string name="error_143_reason">Odmowa dostępu do API</string>
|
||||
<string name="error_144_reason">Nie znaleziono zasobu API</string>
|
||||
<string name="error_145_reason">Brak danych</string>
|
||||
<string name="error_146_reason">Plan lekcji nie jest publiczny</string>
|
||||
<string name="error_147_reason">Brak dostępu do zasobu</string>
|
||||
<string name="error_148_reason">Nieprawidłowe parametry</string>
|
||||
<string name="error_149_reason">Nieprawidłowy zasób</string>
|
||||
<string name="error_150_reason">Szczęśliwy numerek nie jest aktywny</string>
|
||||
<string name="error_151_reason">Uwagi nie są publiczne</string>
|
||||
<string name="error_152_reason">Brak tokenu logowania Synergia</string>
|
||||
<string name="error_153_reason">Nieprawidłowy token logowania Synergia</string>
|
||||
<string name="error_154_reason">Brak ID sesji Synergia</string>
|
||||
<string name="error_155_reason">Brak dostępu do Wiadomości</string>
|
||||
<string name="error_156_reason">Brak dostępu do Synergii</string>
|
||||
<string name="error_157_reason">Brak ID sesji Wiadomości</string>
|
||||
<string name="error_158_reason">Odmowa dostępu do Portalu Librus</string>
|
||||
<string name="error_159_reason">API Portalu Librus wyłączone</string>
|
||||
<string name="error_160_reason">Konto Synergia zostało rozłączone</string>
|
||||
<string name="error_161_reason">Inny błąd Portalu Librus</string>
|
||||
<string name="error_162_reason">Nie znaleziono konta Synergia</string>
|
||||
<string name="error_163_reason">Inny błąd logowania do Portalu Librus</string>
|
||||
<string name="error_164_reason">ERROR_LOGIN_LIBRUS_PORTAL_CODE_EXPIRED</string>
|
||||
<string name="error_165_reason">ERROR_LOGIN_LIBRUS_PORTAL_CODE_REVOKED</string>
|
||||
<string name="error_166_reason">ERROR_LOGIN_LIBRUS_PORTAL_NO_CLIENT_ID</string>
|
||||
<string name="error_167_reason">ERROR_LOGIN_LIBRUS_PORTAL_NO_CODE</string>
|
||||
<string name="error_168_reason">ERROR_LOGIN_LIBRUS_PORTAL_NO_REFRESH</string>
|
||||
<string name="error_169_reason">ERROR_LOGIN_LIBRUS_PORTAL_NO_REDIRECT</string>
|
||||
<string name="error_170_reason">ERROR_LOGIN_LIBRUS_PORTAL_UNSUPPORTED_GRANT</string>
|
||||
<string name="error_171_reason">ERROR_LOGIN_LIBRUS_PORTAL_INVALID_CLIENT_ID</string>
|
||||
<string name="error_172_reason">ERROR_LOGIN_LIBRUS_PORTAL_REFRESH_INVALID</string>
|
||||
<string name="error_173_reason">ERROR_LOGIN_LIBRUS_PORTAL_REFRESH_REVOKED</string>
|
||||
<string name="error_174_reason">ERROR_LIBRUS_SYNERGIA_OTHER</string>
|
||||
<string name="error_175_reason">ERROR_LIBRUS_SYNERGIA_MAINTENANCE</string>
|
||||
|
||||
<string name="error_201_reason">ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_LOGIN</string>
|
||||
<string name="error_202_reason">ERROR_LOGIN_MOBIDZIENNIK_WEB_OLD_PASSWORD</string>
|
||||
<string name="error_203_reason">ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_DEVICE</string>
|
||||
<string name="error_204_reason">ERROR_LOGIN_MOBIDZIENNIK_WEB_ARCHIVED</string>
|
||||
<string name="error_205_reason">ERROR_LOGIN_MOBIDZIENNIK_WEB_MAINTENANCE</string>
|
||||
<string name="error_206_reason">ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_ADDRESS</string>
|
||||
<string name="error_210_reason">ERROR_LOGIN_MOBIDZIENNIK_WEB_OTHER</string>
|
||||
<string name="error_211_reason">ERROR_MOBIDZIENNIK_WEB_ACCESS_DENIED</string>
|
||||
<string name="error_212_reason">ERROR_MOBIDZIENNIK_WEB_NO_SESSION_KEY</string>
|
||||
<string name="error_216_reason">ERROR_MOBIDZIENNIK_WEB_NO_SESSION_VALUE</string>
|
||||
<string name="error_213_reason">ERROR_MOBIDZIENNIK_WEB_NO_SERVER_ID</string>
|
||||
<string name="error_214_reason">ERROR_MOBIDZIENNIK_WEB_INVALID_RESPONSE</string>
|
||||
<string name="error_215_reason">ERROR_LOGIN_MOBIDZIENNIK_WEB_NO_SESSION_ID</string>
|
||||
|
||||
<string name="error_301_reason">ERROR_LOGIN_VULCAN_INVALID_SYMBOL</string>
|
||||
<string name="error_302_reason">ERROR_LOGIN_VULCAN_INVALID_TOKEN</string>
|
||||
<string name="error_309_reason">ERROR_LOGIN_VULCAN_INVALID_PIN</string>
|
||||
<string name="error_310_reason">ERROR_LOGIN_VULCAN_INVALID_PIN_0_REMAINING</string>
|
||||
<string name="error_311_reason">ERROR_LOGIN_VULCAN_INVALID_PIN_1_REMAINING</string>
|
||||
<string name="error_312_reason">ERROR_LOGIN_VULCAN_INVALID_PIN_2_REMAINING</string>
|
||||
<string name="error_321_reason">ERROR_LOGIN_VULCAN_EXPIRED_TOKEN</string>
|
||||
<string name="error_322_reason">ERROR_LOGIN_VULCAN_OTHER</string>
|
||||
<string name="error_330_reason">ERROR_LOGIN_VULCAN_ONLY_KINDERGARTEN</string>
|
||||
<string name="error_331_reason">ERROR_LOGIN_VULCAN_NO_PUPILS</string>
|
||||
<string name="error_340_reason">ERROR_VULCAN_API_MAINTENANCE</string>
|
||||
<string name="error_341_reason">ERROR_VULCAN_API_BAD_REQUEST</string>
|
||||
<string name="error_342_reason">ERROR_VULCAN_API_OTHER</string>
|
||||
|
||||
<string name="error_401_reason">ERROR_LOGIN_IDZIENNIK_WEB_INVALID_LOGIN</string>
|
||||
<string name="error_402_reason">ERROR_LOGIN_IDZIENNIK_WEB_INVALID_SCHOOL_NAME</string>
|
||||
<string name="error_403_reason">ERROR_LOGIN_IDZIENNIK_WEB_PASSWORD_CHANGE_NEEDED</string>
|
||||
<string name="error_404_reason">ERROR_LOGIN_IDZIENNIK_WEB_MAINTENANCE</string>
|
||||
<string name="error_405_reason">ERROR_LOGIN_IDZIENNIK_WEB_SERVER_ERROR</string>
|
||||
<string name="error_410_reason">ERROR_LOGIN_IDZIENNIK_WEB_OTHER</string>
|
||||
<string name="error_411_reason">ERROR_LOGIN_IDZIENNIK_WEB_API_NO_ACCESS</string>
|
||||
<string name="error_420_reason">ERROR_LOGIN_IDZIENNIK_WEB_NO_SESSION</string>
|
||||
<string name="error_421_reason">ERROR_LOGIN_IDZIENNIK_WEB_NO_AUTH</string>
|
||||
<string name="error_422_reason">ERROR_LOGIN_IDZIENNIK_WEB_NO_BEARER</string>
|
||||
<string name="error_430_reason">ERROR_IDZIENNIK_WEB_ACCESS_DENIED</string>
|
||||
<string name="error_431_reason">ERROR_IDZIENNIK_WEB_OTHER</string>
|
||||
<string name="error_432_reason">ERROR_IDZIENNIK_WEB_MAINTENANCE</string>
|
||||
<string name="error_433_reason">ERROR_IDZIENNIK_WEB_SERVER_ERROR</string>
|
||||
<string name="error_434_reason">ERROR_IDZIENNIK_WEB_PASSWORD_CHANGE_NEEDED</string>
|
||||
<string name="error_440_reason">ERROR_LOGIN_IDZIENNIK_FIRST_NO_SCHOOL_YEAR</string>
|
||||
<string name="error_441_reason">ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA</string>
|
||||
<string name="error_450_reason">ERROR_IDZIENNIK_API_ACCESS_DENIED</string>
|
||||
<string name="error_451_reason">ERROR_IDZIENNIK_API_OTHER</string>
|
||||
|
||||
<string name="error_801_reason">ERROR_TEMPLATE_WEB_OTHER</string>
|
||||
|
||||
<string name="error_900_reason">EXCEPTION_API_TASK</string>
|
||||
<string name="error_901_reason">EXCEPTION_LOGIN_LIBRUS_API_TOKEN</string>
|
||||
<string name="error_902_reason">EXCEPTION_LOGIN_LIBRUS_PORTAL_TOKEN</string>
|
||||
<string name="error_903_reason">EXCEPTION_LIBRUS_PORTAL_SYNERGIA_TOKEN</string>
|
||||
<string name="error_904_reason">EXCEPTION_LIBRUS_API_REQUEST</string>
|
||||
<string name="error_905_reason">EXCEPTION_LIBRUS_SYNERGIA_REQUEST</string>
|
||||
<string name="error_906_reason">EXCEPTION_MOBIDZIENNIK_WEB_REQUEST</string>
|
||||
<string name="error_907_reason">EXCEPTION_VULCAN_API_REQUEST</string>
|
||||
<string name="error_910_reason">EXCEPTION_NOTIFY_AND_SYNC</string>
|
||||
<string name="error_911_reason">EXCEPTION_LIBRUS_MESSAGES_REQUEST</string>
|
||||
<string name="error_912_reason">EXCEPTION_IDZIENNIK_WEB_REQUEST</string>
|
||||
<string name="error_913_reason">EXCEPTION_IDZIENNIK_WEB_API_REQUEST</string>
|
||||
<string name="error_914_reason">EXCEPTION_IDZIENNIK_API_REQUEST</string>
|
||||
|
||||
<string name="error_1201_reason">Nie podano parametrów</string>
|
||||
</resources>
|
@ -572,7 +572,7 @@
|
||||
<string name="profile_menu_open_settings">Ustawienia</string>
|
||||
<string name="profile_menu_remove">Usuń profil</string>
|
||||
<string name="profile_menu_remove_confirm">Potwierdź usunięcie</string>
|
||||
<string name="profile_menu_remove_confirm_text_format">Zamierzasz usunąć profil %s. Oznacza to usunięcie z aplikacji wszystkich danych powiązanych z tym profilem (ocen, planu lekcji, sprawdzianów…).\n\nWiększość danych będziesz mógł pobrać na nowo poprzez ponowne zalogowanie się.\n\nCzy rzeczywiście chcesz usunąć profil %s?</string>
|
||||
<string name="profile_menu_remove_confirm_text_format">Zamierzasz usunąć profil <b>%s</b>. Oznacza to usunięcie z aplikacji wszystkich danych powiązanych z tym profilem (ocen, planu lekcji, sprawdzianów…).\n\nWiększość danych będziesz mógł pobrać na nowo poprzez ponowne zalogowanie się.\n\nCzy rzeczywiście chcesz usunąć profil %s?</string>
|
||||
<string name="rate_snackbar_negative">Nigdy</string>
|
||||
<string name="rate_snackbar_neutral">Później</string>
|
||||
<string name="rate_snackbar_positive">Oceń teraz</string>
|
||||
@ -1022,4 +1022,8 @@
|
||||
<string name="dialog_event_manual_date_today">dzisiaj (%s)</string>
|
||||
<string name="dialog_event_manual_date_next_week">następny %s (%s)</string>
|
||||
<string name="dialog_event_manual_no_lessons">Nie ma lekcji tego dnia</string>
|
||||
<string name="dialog_profile_remove_success">Profil został usunięty.</string>
|
||||
<string name="snackbar_error_text">Wystąpił błąd</string>
|
||||
<string name="dialog_sync_view_list_title">Synchronizacja ręczna</string>
|
||||
<string name="timetable_no_subject_name">(brak nazwy)</string>
|
||||
</resources>
|
||||
|
@ -5,8 +5,8 @@ buildscript {
|
||||
kotlin_version = '1.3.50'
|
||||
|
||||
release = [
|
||||
versionName: "3.9.4-dev",
|
||||
versionCode: 3090400
|
||||
versionName: "3.9.7-dev",
|
||||
versionCode: 3090700
|
||||
]
|
||||
|
||||
setup = [
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
|
Reference in New Issue
Block a user