FossifyOrg / Clock

Combination of a beautiful clock with widget, alarm, stopwatch & timer, no ads
https://www.fossify.org
GNU General Public License v3.0
233 stars 15 forks source link

FEAT: added alarm and timer export and import functionality #53

Open ronniedroid opened 6 months ago

ronniedroid commented 6 months ago

What is it?

Description of the changes in your PR

Acknowledgement

ronniedroid commented 6 months ago

Hey,

So this is fully working and tested, it does export the alarms and import them correctly. One Issue though, let's say you are importing a json array with three alarm objects, all three alarms will be correctly imported into the database, but the alarms view sometimes shows only the first item, sometimes it shows two items and sometimes it shows all imported items. However all the alarms show up on app restart.

I tried debugging this a little but I am not very good it this, here is what I tested:

I am guessing this has to do with main vs background threat or both activities are not using the same instant of the DBHelper.

Any help would be appreciated.

naveensingh commented 6 months ago

I'll take a look at this later but in the future, please create a discussion or feature request first (because we may not want to implement everything that is suggested):

If you try fixing a bug or adding a new feature, make sure that it is already reported at the given repository and the report is open without label needs triage. If the given issue is closed or still has needs triage label, your pull request will be rejected. The only exception are critical bugs that we weren't able to classify yet.

https://github.com/FossifyOrg/General-Discussion?tab=readme-ov-file#contribution-rules-for-developers

ronniedroid commented 6 months ago

I'll take a look at this later but in the future, please create a discussion or feature request first (because we may not want to implement everything that is suggested):

@naveensingh I am sorry, I did read the contribution guidelines or I would not have ticked it, but I just have missed that part and I am sorry for that.

I do change ROMs a lot and every time I have to setup all my alarms again (I have many) and this was a feature I really needed so hopefully you will consider it :-)

ronniedroid commented 5 months ago

I moved the export and import to the settings and removed them from the menu, the exporter now exports both alarms and timers, the import is broken now, will fix it soon.

ronniedroid commented 5 months ago

@naveensingh This might not be a priority, but I did complete this PR, now timers and alarms are exported and imported together and I have done my best to handle errors especially while importing, your review of this when you have time is greatly appreciated :-)

Aga-C commented 5 months ago
  1. Why have you created an Export and import section in Settings? In all other apps it's called Migrating, and the string for it is in Commons.
  2. Why there's so much empty space under Export data?

image

  1. To make it look more as in other apps, strings should rather be Export alarms and timers and Import alarms and timers.
  2. In other apps, we don't have a toast informing the user that export/import has been aborted. It only happens while pressing back on save, so the user is aware of what they have done.
  3. Can you make string Partial import due to wrong data more similar to other apps? In other apps, we have Importing some entries failed and Importing some events failed.

We should keep consistent behavior, looks and naming between all the apps. Also, where it's possible, we should use strings defined in Commons.

ronniedroid commented 5 months ago

@Aga-C I fixed all of the above.

For the space, I had put a subtitle but it was not showing when building, so I just removed it and now there is no space.

I did not completely understand point 4, I did remove the toast messages for aborting, I just don't know what "pressing back on save" means.

I am sorry for the inconveniences, next time I will make sure a string is available in the commons or that it is consistent with the other apps.

BTW, alarms and timers are populated correctly in the app now when imported, no need to restart the app to see them.

Aga-C commented 5 months ago

It seems to work fine, but there are two edge cases where it behaves strange.

First issue - duplicating alarms

When you import the same alarms and timers as you currently have in the app, the import:

I think the behavior should be consistent in both tabs, either with duplicating or not. IMO, we shouldn't duplicate at all.

Second issue - overwriting timers

Duplicate checking in Timers while import shouldn't remove already edited timers. I did something like this:

  1. Created a timer.
  2. Exported data.
  3. Changed that timer's sound and time.
  4. Imported data.

Instead of creating a new entry with old data, it has overwritten the current entry. I assume you check it only by ID (I haven't checked the code, just testing from the user perspective), because when I created another timer with exactly the same name, time and sound, it hasn't overwritten it.

ronniedroid commented 5 months ago

I will test this tomorrow and see what is going on. I hadn't thought about duplicates tbh, thank you for testing.

ronniedroid commented 5 months ago

Ok, for the first problem, I think I got what the issue is, not very sure how to fix it yet.

first, I was not backing up the isEnabled state, and was always setting it to false, this made a problem in comparing to see the if alarm !in dbHelper.getAlarms(), that fixed, the other issue is, the dbHelper.insertAlarm(alarm) doesn't take the id from the imported data, it inserts it with a new id (generated automatically) which causes the alarms that have been imported to be inserted again and again.

the values of insertAlarm are generated here

    private fun fillAlarmContentValues(alarm: Alarm): ContentValues {
        return ContentValues().apply {
            put(COL_TIME_IN_MINUTES, alarm.timeInMinutes)
            put(COL_DAYS, alarm.days)
            put(COL_IS_ENABLED, alarm.isEnabled)
            put(COL_VIBRATE, alarm.vibrate)
            put(COL_SOUND_TITLE, alarm.soundTitle)
            put(COL_SOUND_URI, alarm.soundUri)
            put(COL_LABEL, alarm.label)
            put(COL_ONE_SHOT, alarm.oneShot)
        }
    }

What do you suggest we do about this? Make an insertFromBackup function in DBHelper?

For the second issue, I think this is causing it

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertOrUpdateTimer(timer: Timer): Long

EDIT: I have forgotten to push the latest changes where I am checking if the entries are in the database already or not.

Aga-C commented 5 months ago

But if you will consider ID in alarm data, you will probably have the same issue in alarms as there's now in timers. I think it should be manually checked if an entry with the same fields already exists. People won't have an enormous amount of alarms, so it shouldn't be slow.

ronniedroid commented 5 months ago

But if you will consider ID in alarm data, you will probably have the same issue in alarms as there's now in timers. I think it should be manually checked if an entry with the same fields already exists. People won't have an enormous amount of alarms, so it shouldn't be slow.

I already fixed the alarms by comparing every entry but the ID.

Same did not work for the timers, as the insertOrUpdate function is updating the timer with the same ID, will figure that out too.

ronniedroid commented 5 months ago

@Aga-C

Ok so, it all is working now.

for the timers, I am comparing all entries but the ID, and if it does not exist, I am updating the ID of the inserted timers with existingTimers.last().id?.plus(1), so it would make a new timer and not replace an already existing one.

I am not sure if this is the best approach, so I will await your comments.

Aga-C commented 5 months ago

In timers, if you export two entries with the same name (but different time), only one of them is imported. You can test on a JSON I've exported: Export alarms and timers_2024_04_22_07_36_54.json

Also, I've found another problem - if you have empty timers list, there's an exception and nothing gets imported.

ronniedroid commented 5 months ago

@Aga-C fixed, the problem was that I was inserting new alarms with the id set to last timer in the list + 1, so now I am just making sure to set the id to 1 if no timers are available.

Aga-C commented 5 months ago

It seems to be working fine. The only thing that bothers me is that whenever there are duplicates, it says Importing some entries failed. It sounds like there was an error, when in fact there wasn't any.

In Calendar, it works like this:

ronniedroid commented 5 months ago

I agree, will update soon.

ronniedroid commented 5 months ago

and it is done.