Merge lp:~suutari-olli/openlp/click-slide-to-go-live-from-blank into lp:openlp

Proposed by Azaziah on 2016-03-15
Status: Superseded
Proposed branch: lp:~suutari-olli/openlp/click-slide-to-go-live-from-blank
Merge into: lp:openlp
Diff against target: 235 lines (+137/-2)
4 files modified
openlp/core/common/settings.py (+1/-0)
openlp/core/ui/generaltab.py (+7/-0)
openlp/core/ui/slidecontroller.py (+32/-2)
tests/functional/openlp_core_ui/test_slidecontroller.py (+97/-0)
To merge this branch: bzr merge lp:~suutari-olli/openlp/click-slide-to-go-live-from-blank
Reviewer Review Type Date Requested Status
Tomas Groth 2016-03-15 Needs Fixing on 2016-03-15
Review via email: mp+289026@code.launchpad.net

This proposal has been superseded by a proposal from 2016-04-01.

Description of the change

This branch introduces the functionality of unblanking
display from Blank to Black/Theme/Desktop for:

a) Clicking slide in “Live panel”
b) Next/Previous shortcuts (Green arrows)
c) Go to verse x.
d) When starting automatic playback (To end or Loop)
Also added “Unblank display when changing slide in Live” to advanced
options tab for disabling/enabling this behavior for a-c.

Additionally this branch also includes fix for bug
https://bugs.launchpad.net/openlp/+bug/1531691
Do note that this branch does not fix this for Escape item blanking,
creating yet an another Escape exclusive bug.

The only reason Escape item has been a good alternative for other
blank to methods is the functionality of resuming Live by clicking
slides and the fact it worked in single screen scenarios.
I can’t see any reason why it should not be removed after this branch
is merged since the single screen issue was already fixed earlier.

Test coverage is not yet increased.
If it must be done, what has to be tested?

--------------------------------
lp:~suutari-olli/openlp/click-slide-to-go-live-from-blank (revision 2630)
[←[1;32mSUCCESS←[1;m] https://ci.openlp.io/job/Branch-01-Pull/1318/
[←[1;32mSUCCESS←[1;m] https://ci.openlp.io/job/Branch-02-Functional-Tests/1240/
[←[1;32mSUCCESS←[1;m] https://ci.openlp.io/job/Branch-03-Interface-Tests/1179/
[←[1;32mSUCCESS←[1;m] https://ci.openlp.io/job/Branch-04a-Windows_Functional_Tests/1014/
[←[1;32mSUCCESS←[1;m] https://ci.openlp.io/job/Branch-04b-Windows_Interface_Tests/605/
[←[1;32mSUCCESS←[1;m] https://ci.openlp.io/job/Branch-05a-Code_Analysis/672/
[←[1;31mFAILURE←[1;m] https://ci.openlp.io/job/Branch-05b-Test_Coverage/540/

To post a comment you must log in.
2631. By Azaziah on 2016-03-15

Removed duplicate: self.on_hide_display(True)
(Was trying to create/test a test but failed and forgot to take it away)

Tomas Groth (tomasgroth) wrote :

Just tested a bit.
You have introduced the "Click live slide to unblank" setting, but a "Unblank display when adding new item" also exists in the general tab. You should probably move yours to be under the exiting one to keep similar settings in the same place. Currently your code doesn't honor the "Unblank display when adding new item", which it will have to do. As it is now the item goes live no matter if the setting is enabled or not.
Also the new setting should be "false" as default, this is new behavior, so users should enabled it if they want it.
Also added a code-comment below.

review: Needs Fixing
2632. By Azaziah on 2016-03-15

In this merge:
- Moved setting for controlling unblanking behaviour to General options tab.
- Removed it from advanced tab
- Changed default setting to "no"
- Looped playback (once or to end) is now linked to this setting
- Unblanking slides on click -.- no longer unblanks display when sending new items live if
  "Unblank display when sending new item to live" is not enabled. -.-
- Doubleclicking preview -.- ^^
- Improved some comments

To do:
Test(s)?

Azaziah (suutari-olli) wrote :

Hi Tomas and thank you for your comments!

"Unblank display when adding new item" also exists in the general tab. You should probably move yours to be under the exiting one to keep similar settings in the same place. Currently your code doesn't honor the "Unblank display when adding new item

# Done and Done, now also honoring double clicking preview

Also the new setting should be "false" as default, this is new behavior, so users should enabled it if they want it.

# Done
# Currently this is default behavior for Escape item and probably easier
to use than our current blank to modes. I think this and some other settings
should eventually be changed to be more user friendly by default.

Tomas Groth (tomasgroth) wrote :

Looks good now. As you mention in one of your source-comments the previous slide is shortly visible when display is unblanked. Don't know if it can be helped.
Added a comment to the code below.
Besides that, you need tests :)

review: Needs Fixing
Azaziah (suutari-olli) wrote :

Thanks again,

if by previous slide being shortly visible you mean it happens once you change slide inside the Live Panel
and the transition effect is applied, yes that can be changed. I've heard people complaining there's no transition effects when unblanking or changing items so maybe it should be left as it is since it would mean loosing effects.

If you were talking about this happening on song edit:
Think it would be possible but would require quite a effort,
maybe we can let it pass for the time being, it's still mostly fixed.

I really suck at writing tests, is one enough for a rookie?

I also replied to the code comment.

2633. By Azaziah on 2016-04-01

Added 3 tests for replacing Live item from service manager while display is blanked. (One for each)

2634. By Azaziah on 2016-04-01

Merged to trunk (1.4.2016)

2635. By Azaziah on 2016-04-01

- Fixed issue where PPT/Impress is not unblanked on "Previous/Next" (Green arrows).

2636. By Azaziah on 2016-04-03

Changed Live to live (lowercaps) for controlling this setting to match other settings.

2637. By Azaziah on 2016-04-10

Merged trunk on 11.4.2016

2638. By Azaziah on 2016-04-12

Merged trunk on 13.4.16

2639. By Azaziah on 2016-04-13

Changed spelling of live back to Live (Capitalized) on settings.

2640. By Azaziah on 2016-04-17

- Fixed bug 1462420 - Double clicking Preview adds item to Service countless times
  (Added hidden setting for controlling this, it is set to True once double clicking
  has added item to Service and gets reset to False once new item is sent to preview.

2641. By Azaziah on 2016-04-17

Fixed bug 1462420 (Double click on the preview duplicated the element in the service manger)
- Added a hidden setting for controlling this behaviour.
 It is reset if any item is sent to preview from library.
 Sending the same item to service multiple times is still possible by using the "Add icon"

2642. By Azaziah on 2016-04-17

Turned the new setting into question.

2643. By Azaziah on 2016-04-17

Made a better fix for fixing bug where display is unblanked on editing current live item.
This now sets a hidden setting to true while processing Live item and then changes it back to false.
Display is thus not unblanked at all during the process. (Old fix showed the edited slide for a small time)

Downside: All the new tests were based on the old method and thus they were removed.

2644. By Azaziah on 2016-04-17

Made a better fix for fixing bug where display is unblanked on editing current live item.
This now sets a hidden setting to true while processing Live item and then changes it back to false.
Display is thus not unblanked at all during the process. (Old fix showed the edited slide for a small time)

Downside: All the new tests were based on the old method and thus they were removed.

2645. By Azaziah on 2016-04-17

- Removed _ from end of one setting name.
- Fixed ident on replace_service_manager

2646. By Azaziah on 2016-04-20

- Added two tests for checking if doubleclicking preview should add item to service or send it to live.

2647. By Azaziah on 2016-04-20

Noticed I had removed one test from end of the file, added it back.

2648. By Azaziah on 2016-04-27

Added this to program startup code, should replace_service_manager_item ever crash the program.

Settings().setValue('core/is live item edited and replaced', False)

2649. By Azaziah on 2016-06-13

merged trunk on 14.6.16

2650. By Azaziah on 2016-06-26

- Turned the two new hidden settings into registry flags

2651. By Azaziah on 2016-06-26

Comment cleanup / Improvements

2652. By Azaziah on 2016-06-26

- Merged trunk on 27.6.16

2653. By Azaziah on 2016-07-14

- Tried to make the new text work with the registry changes but failed.
 > Test is broken, do not merge!

2654. By Azaziah on 2016-07-14

Merged trunk on 14.7.16

2655. By Azaziah on 2016-07-14

pep8 fixes, test still broken.

2656. By Azaziah on 2016-07-16

Fixed the tests.

2657. By Azaziah on 2016-07-16

- Reduced comments
- Removed unrequired reg_value from test.

2658. By Azaziah on 2016-07-17

- Fixed the issue where items sent to Preview from Service may cause tracebacks.

2659. By Azaziah on 2016-07-17

- Moved the 2nd new registry flag from one init to an another init which also has the 1st

2660. By Azaziah on 2016-07-17

- Moved them to another init since something broke

2661. By Azaziah on 2016-07-17

- removed one unrequired if statement.

2662. By Azaziah on 2016-07-31

- Merged trunk on 31.7.16

2663. By Azaziah on 2016-08-09

- Merged trunk on 10/8/16.

2664. By Azaziah on 2016-08-10

- Merged trunk and resolved conflict that was created by ui-messages-part-1 branch.

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'openlp/core/common/settings.py'
--- openlp/core/common/settings.py 2016-03-15 21:34:58 +0000
+++ openlp/core/common/settings.py 2016-04-01 13:12:45 +0000
@@ -141,6 +141,7 @@
141 'core/auto preview': False,141 'core/auto preview': False,
142 'core/audio start paused': True,142 'core/audio start paused': True,
143 'core/auto unblank': False,143 'core/auto unblank': False,
144 'core/click live slide to unblank': False,
144 'core/blank warning': False,145 'core/blank warning': False,
145 'core/ccli number': '',146 'core/ccli number': '',
146 'core/has run wizard': False,147 'core/has run wizard': False,
147148
=== modified file 'openlp/core/ui/generaltab.py'
--- openlp/core/ui/generaltab.py 2016-01-16 20:13:41 +0000
+++ openlp/core/ui/generaltab.py 2016-04-01 13:12:45 +0000
@@ -173,6 +173,9 @@
173 self.auto_unblank_check_box = QtWidgets.QCheckBox(self.settings_group_box)173 self.auto_unblank_check_box = QtWidgets.QCheckBox(self.settings_group_box)
174 self.auto_unblank_check_box.setObjectName('auto_unblank_check_box')174 self.auto_unblank_check_box.setObjectName('auto_unblank_check_box')
175 self.settings_layout.addRow(self.auto_unblank_check_box)175 self.settings_layout.addRow(self.auto_unblank_check_box)
176 self.click_live_slide_to_unblank_check_box = QtWidgets.QCheckBox(self.settings_group_box)
177 self.click_live_slide_to_unblank_check_box.setObjectName('click_live_slide_to_unblank_')
178 self.settings_layout.addRow(self.click_live_slide_to_unblank_check_box)
176 self.auto_preview_check_box = QtWidgets.QCheckBox(self.settings_group_box)179 self.auto_preview_check_box = QtWidgets.QCheckBox(self.settings_group_box)
177 self.auto_preview_check_box.setObjectName('auto_preview_check_box')180 self.auto_preview_check_box.setObjectName('auto_preview_check_box')
178 self.settings_layout.addRow(self.auto_preview_check_box)181 self.settings_layout.addRow(self.auto_preview_check_box)
@@ -217,6 +220,8 @@
217 self.save_check_service_check_box.setText(translate('OpenLP.GeneralTab',220 self.save_check_service_check_box.setText(translate('OpenLP.GeneralTab',
218 'Prompt to save before starting a new service'))221 'Prompt to save before starting a new service'))
219 self.auto_unblank_check_box.setText(translate('OpenLP.GeneralTab', 'Unblank display when adding new live item'))222 self.auto_unblank_check_box.setText(translate('OpenLP.GeneralTab', 'Unblank display when adding new live item'))
223 self.click_live_slide_to_unblank_check_box.setText(translate('OpenLP.GeneralTab',
224 'Unblank display when changing slide in Live'))
220 self.auto_preview_check_box.setText(translate('OpenLP.GeneralTab',225 self.auto_preview_check_box.setText(translate('OpenLP.GeneralTab',
221 'Automatically preview next item in service'))226 'Automatically preview next item in service'))
222 self.timeout_label.setText(translate('OpenLP.GeneralTab', 'Timed slide interval:'))227 self.timeout_label.setText(translate('OpenLP.GeneralTab', 'Timed slide interval:'))
@@ -250,6 +255,7 @@
250 self.password_edit.setText(settings.value('songselect password'))255 self.password_edit.setText(settings.value('songselect password'))
251 self.save_check_service_check_box.setChecked(settings.value('save prompt'))256 self.save_check_service_check_box.setChecked(settings.value('save prompt'))
252 self.auto_unblank_check_box.setChecked(settings.value('auto unblank'))257 self.auto_unblank_check_box.setChecked(settings.value('auto unblank'))
258 self.click_live_slide_to_unblank_check_box.setChecked(settings.value('click live slide to unblank'))
253 self.display_on_monitor_check.setChecked(self.screens.display)259 self.display_on_monitor_check.setChecked(self.screens.display)
254 self.warning_check_box.setChecked(settings.value('blank warning'))260 self.warning_check_box.setChecked(settings.value('blank warning'))
255 self.auto_open_check_box.setChecked(settings.value('auto open'))261 self.auto_open_check_box.setChecked(settings.value('auto open'))
@@ -287,6 +293,7 @@
287 settings.setValue('update check', self.check_for_updates_check_box.isChecked())293 settings.setValue('update check', self.check_for_updates_check_box.isChecked())
288 settings.setValue('save prompt', self.save_check_service_check_box.isChecked())294 settings.setValue('save prompt', self.save_check_service_check_box.isChecked())
289 settings.setValue('auto unblank', self.auto_unblank_check_box.isChecked())295 settings.setValue('auto unblank', self.auto_unblank_check_box.isChecked())
296 settings.setValue('click live slide to unblank', self.click_live_slide_to_unblank_check_box.isChecked())
290 settings.setValue('auto preview', self.auto_preview_check_box.isChecked())297 settings.setValue('auto preview', self.auto_preview_check_box.isChecked())
291 settings.setValue('loop delay', self.timeout_spin_box.value())298 settings.setValue('loop delay', self.timeout_spin_box.value())
292 settings.setValue('ccli number', self.number_edit.displayText())299 settings.setValue('ccli number', self.number_edit.displayText())
293300
=== modified file 'openlp/core/ui/slidecontroller.py'
--- openlp/core/ui/slidecontroller.py 2016-03-31 16:34:22 +0000
+++ openlp/core/ui/slidecontroller.py 2016-04-01 13:12:45 +0000
@@ -789,11 +789,28 @@
789 def replace_service_manager_item(self, item):789 def replace_service_manager_item(self, item):
790 """790 """
791 Replacement item following a remote edit791 Replacement item following a remote edit
792 This action also takes place when a song that is sent to live from Service Manager is edited.
793 If display is blanked, this will update the song and then re-blank the display.
794 As result, lyrics are flashed on screen for a very short time before re-blanking happens. (Bug)
795 This happens only when Automatic unblanking is enabled when new item is sen to Live,
796 if it's not enabled they won't flash.
792797
793 :param item: The current service item798 :param item: The current service item
794 """799 """
795 if item == self.service_item:800 if item == self.service_item:
796 self._process_item(item, self.preview_widget.current_slide_number())801 if not self.hide_mode():
802 self._process_item(item, self.preview_widget.current_slide_number())
803 # "isChecked" method is required for checking blanks, on_xx_display(False) does not work.
804 elif self.hide_mode():
805 if self.blank_screen.isChecked():
806 self._process_item(item, self.preview_widget.current_slide_number())
807 self.on_blank_display(True)
808 elif self.theme_screen.isChecked():
809 self._process_item(item, self.preview_widget.current_slide_number())
810 self.on_theme_display(True)
811 elif self.desktop_screen.isChecked():
812 self._process_item(item, self.preview_widget.current_slide_number())
813 self.on_hide_display(True)
797814
798 def add_service_manager_item(self, item, slide_no):815 def add_service_manager_item(self, item, slide_no):
799 """816 """
@@ -1090,6 +1107,14 @@
1090 self.log_debug('Could not get lock in slide_selected after waiting %f, skip to avoid deadlock.'1107 self.log_debug('Could not get lock in slide_selected after waiting %f, skip to avoid deadlock.'
1091 % timeout)1108 % timeout)
1092 return1109 return
1110 # If "click live slide to unblank" is enabled, unblank the display.
1111 # Note: If this if statement is placed at the bottom of this function instead of top slide transitions are lost.
1112 if self.is_live and Settings().value('core/click live slide to unblank'):
1113 # With this display stays blanked when "auto unblank" setting is not enabled and new item is sent to Live.
1114 if not Settings().value('core/auto unblank') and start:
1115 ()
1116 else:
1117 Registry().execute('slidecontroller_live_unblank')
1093 row = self.preview_widget.current_slide_number()1118 row = self.preview_widget.current_slide_number()
1094 old_selected_row = self.selected_row1119 old_selected_row = self.selected_row
1095 self.selected_row = 01120 self.selected_row = 0
@@ -1258,6 +1283,8 @@
1258 self.play_slides_once.setText(UiStrings().PlaySlidesToEnd)1283 self.play_slides_once.setText(UiStrings().PlaySlidesToEnd)
1259 self.play_slides_menu.setDefaultAction(self.play_slides_loop)1284 self.play_slides_menu.setDefaultAction(self.play_slides_loop)
1260 self.play_slides_once.setChecked(False)1285 self.play_slides_once.setChecked(False)
1286 if Settings().value('core/click live slide to unblank'):
1287 Registry().execute('slidecontroller_live_unblank')
1261 else:1288 else:
1262 self.play_slides_loop.setIcon(build_icon(':/media/media_time.png'))1289 self.play_slides_loop.setIcon(build_icon(':/media/media_time.png'))
1263 self.play_slides_loop.setText(UiStrings().PlaySlidesInLoop)1290 self.play_slides_loop.setText(UiStrings().PlaySlidesInLoop)
@@ -1281,6 +1308,8 @@
1281 self.play_slides_loop.setText(UiStrings().PlaySlidesInLoop)1308 self.play_slides_loop.setText(UiStrings().PlaySlidesInLoop)
1282 self.play_slides_menu.setDefaultAction(self.play_slides_once)1309 self.play_slides_menu.setDefaultAction(self.play_slides_once)
1283 self.play_slides_loop.setChecked(False)1310 self.play_slides_loop.setChecked(False)
1311 if Settings().value('core/click live slide to unblank'):
1312 Registry().execute('slidecontroller_live_unblank')
1284 else:1313 else:
1285 self.play_slides_once.setIcon(build_icon(':/media/media_time'))1314 self.play_slides_once.setIcon(build_icon(':/media/media_time'))
1286 self.play_slides_once.setText(UiStrings().PlaySlidesToEnd)1315 self.play_slides_once.setText(UiStrings().PlaySlidesToEnd)
@@ -1342,7 +1371,8 @@
1342 Registry().execute('%s_stop' % self.service_item.name.lower(), [self.service_item, self.is_live])1371 Registry().execute('%s_stop' % self.service_item.name.lower(), [self.service_item, self.is_live])
1343 if self.service_item.is_media():1372 if self.service_item.is_media():
1344 self.on_media_close()1373 self.on_media_close()
1345 self.on_go_live()1374 if Settings().value('core/auto unblank'):
1375 self.on_go_live()
1346 else:1376 else:
1347 self.on_preview_add_to_service()1377 self.on_preview_add_to_service()
13481378
13491379
=== modified file 'tests/functional/openlp_core_ui/test_slidecontroller.py'
--- tests/functional/openlp_core_ui/test_slidecontroller.py 2016-02-27 14:25:31 +0000
+++ tests/functional/openlp_core_ui/test_slidecontroller.py 2016-04-01 13:12:45 +0000
@@ -538,6 +538,103 @@
538 mocked_preview_widget.current_slide_number.assert_called_with()538 mocked_preview_widget.current_slide_number.assert_called_with()
539 mocked_process_item.assert_called_once_with(mocked_item, 7)539 mocked_process_item.assert_called_once_with(mocked_item, 7)
540540
541 def replace_service_manager_item_on_blank_display_test(self):
542 """
543 Test that when the service item is replaced, display remains blanked if it was blanked.
544 """
545 # GIVEN: A slide controller and a new item to add, blanked display.
546 mocked_item = MagicMock()
547 mocked_preview_widget = MagicMock()
548 mocked_preview_widget.current_slide_number = MagicMock()
549 mocked_process_item = MagicMock()
550 slide_controller = SlideController(None)
551 slide_controller.preview_widget = mocked_preview_widget
552 slide_controller._process_item = mocked_process_item
553 slide_controller.service_item = mocked_item
554 slide_controller.hide_menu = MagicMock()
555 slide_controller.hide_mode = MagicMock()
556 slide_controller.hide_mode.return_value = True
557 slide_controller.blank_screen = MagicMock()
558 slide_controller.blank_screen.isChecked = MagicMock()
559 slide_controller.blank_screen.isChecked.return_value = True
560 slide_controller.on_blank_display = mocked_item
561 slide_controller.theme_screen = MagicMock()
562 slide_controller.desktop_screen = MagicMock()
563 slide_controller.log_debug = MagicMock()
564
565 # WHEN: The service item is replaced
566 slide_controller.replace_service_manager_item(mocked_item)
567
568 # THEN: The display should remain blanked
569 slide_controller.on_blank_display.assert_called_once_with(True)
570
571 def replace_service_manager_item_on_theme_display_test(self):
572 """
573 Test that when the service item is replaced, display remains blanked if it was blanked.
574 """
575 # GIVEN: A slide controller and a new item to add, blanked display.
576 mocked_item = MagicMock()
577 mocked_preview_widget = MagicMock()
578 mocked_preview_widget.current_slide_number = MagicMock()
579 mocked_process_item = MagicMock()
580 slide_controller = SlideController(None)
581 slide_controller.preview_widget = mocked_preview_widget
582 slide_controller._process_item = mocked_process_item
583 slide_controller.service_item = mocked_item
584 slide_controller.hide_menu = MagicMock()
585 slide_controller.hide_mode = MagicMock()
586 slide_controller.hide_mode.return_value = True
587 slide_controller.blank_screen = MagicMock()
588 slide_controller.blank_screen.isChecked = MagicMock()
589 slide_controller.blank_screen.isChecked.return_value = False
590 slide_controller.theme_screen = MagicMock()
591 slide_controller.theme_screen.isChecked = MagicMock()
592 slide_controller.theme_screen.isChecked.return_value = True
593 slide_controller.on_theme_display = mocked_item
594 slide_controller.desktop_screen = MagicMock()
595 slide_controller.log_debug = MagicMock()
596
597 # WHEN: The service item is replaced
598 slide_controller.replace_service_manager_item(mocked_item)
599
600 # THEN: The display should remain blanked
601 slide_controller.on_theme_display.assert_called_once_with(True)
602
603 def replace_service_manager_item_on_hide_display_test(self):
604 """
605 Test that when the service item is replaced, display remains blanked if it was blanked.
606 """
607 # GIVEN: A slide controller and a new item to add, blanked display.
608 mocked_item = MagicMock()
609 mocked_preview_widget = MagicMock()
610 mocked_preview_widget.current_slide_number = MagicMock()
611 mocked_process_item = MagicMock()
612 slide_controller = SlideController(None)
613 slide_controller.preview_widget = mocked_preview_widget
614 slide_controller._process_item = mocked_process_item
615 slide_controller.service_item = mocked_item
616 slide_controller.hide_menu = MagicMock()
617 slide_controller.hide_mode = MagicMock()
618 slide_controller.hide_mode.return_value = True
619 slide_controller.blank_screen = MagicMock()
620 slide_controller.blank_screen.isChecked = MagicMock()
621 slide_controller.blank_screen.isChecked.return_value = False
622 slide_controller.theme_screen = MagicMock()
623 slide_controller.theme_screen.isChecked = MagicMock()
624 slide_controller.theme_screen.isChecked.return_value = False
625 slide_controller.on_theme_display = mocked_item
626 slide_controller.desktop_screen = MagicMock()
627 slide_controller.desktop_screen.isChecked = MagicMock()
628 slide_controller.desktop_screen.isChecked.return_value = True
629 slide_controller.on_hide_display = MagicMock()
630 slide_controller.log_debug = MagicMock()
631
632 # WHEN: The service item is replaced
633 slide_controller.replace_service_manager_item(mocked_item)
634
635 # THEN: The display should remain blanked
636 slide_controller.on_hide_display.assert_called_once_with(True)
637
541 def on_slide_blank_test(self):638 def on_slide_blank_test(self):
542 """639 """
543 Test on_slide_blank640 Test on_slide_blank