diff --git a/lib/python/Screens/DateTimeInput.py b/lib/python/Screens/DateTimeInput.py new file mode 100644 index 00000000000..a9bdb2a314b --- /dev/null +++ b/lib/python/Screens/DateTimeInput.py @@ -0,0 +1,85 @@ +from time import time + +from Components.ActionMap import HelpableActionMap +from Components.config import ConfigDateTime, config +from Screens.Setup import Setup + + +class DateTime(Setup): + def __init__(self, session, setupSection, default, smallStep=60): + self.dateTime = ConfigDateTime(default, f"{config.usage.date.daylong.value} {config.usage.time.short.value}", increment=smallStep) + Setup.__init__(self, session, setupSection) + self.skinName.insert(0, "SetupDateTime") + self["prevNextActions"] = HelpableActionMap(self, ["PreviousNextActions"], { # This is for users who do not use PREV/NEXT as first/last. + "previous": (self.keyFirst, _("Jump back one hour") if self.bigStep == 3600 else _("Jump back one day")), + "next": (self.keyLast, _("Jump forward one hour") if self.bigStep == 3600 else _("Jump forward one day")) + }, prio=0, description=_("Date Time Input Actions")) + + def changedEntry(self): # This overrides the same class in Setup.py. + current = self["config"].getCurrent() + if current and current[1] == self.dateTime: + if self.dateTime.value < self.minLimit: + self.dateTime.value = self.minLimit + elif self.dateTime.value > self.maxLimit: + self.dateTime.value = self.maxLimit + self["config"].invalidateCurrent() + Setup.changedEntry(self) + + def keyFirst(self): # This overrides the same class in ConfigList.py as part of Setup.py. + current = self["config"].getCurrent() + if current and current[1] == self.dateTime: + self.dateTime.value -= self.bigStep + if self.dateTime.value < self.minLimit: + self.dateTime.value = self.minLimit + self["config"].invalidateCurrent() + + def keyLast(self): # This overrides the same class in ConfigList.py as part of Setup.py. + current = self["config"].getCurrent() + if current and current[1] == self.dateTime: + self.dateTime.value += self.bigStep + if self.dateTime.value > self.maxLimit: + self.dateTime.value = self.maxLimit + self["config"].invalidateCurrent() + + def keySave(self): # This overrides the same class in ConfigList.py as part of Setup.py. + self.close((True, self.dateTime.value)) + + def keyCancel(self): # This overrides the same class in ConfigList.py as part of Setup.py. + self.close((False,)) + + def closeRecursive(self): # This overrides the same class in ConfigList.py as part of Setup.py. + self.close((True,)) + + +class EPGJumpTime(DateTime): + def __init__(self, session, configElement, historyBuffer): + self.minLimit = int(time()) - (historyBuffer * 60) # Now - EPG history buffer length. + self.maxLimit = int(time()) + 2419200 # Now + 4 weeks. + self.smallStep = 3600 # 1 Hour. + self.bigStep = 86400 # 1 Day. + DateTime.__init__(self, session, "EPGJumpTime", default=int(time()), smallStep=self.smallStep) + self.setTitle(_("EPG Jump")) + self["key_green"].setText(_("Jump")) + + def createSetup(self): # This overrides the same class in Setup.py. + configList = [ + (_("Jump time"), self.dateTime, _("Select the time to which the EPG should be positioned. Press LEFT/RIGHT to decrease/increase the time by an hour. Press PREV/NEXT to decrease/increase the time by a day.")) + ] + self["config"].setList(configList) + + +class InstantRecordingEndTime(DateTime): + def __init__(self, session, endTime): + self.minLimit = int(time()) + 60 # Now + 1 minute. + self.maxLimit = int(time()) + 86400 # Now + 1 day. + self.smallStep = 60 # 1 Minute. + self.bigStep = 3600 # 1 Hour. + DateTime.__init__(self, session, "InstantRecordingEndTime", default=endTime, smallStep=self.smallStep) + self.setTitle(_("Instant Recording End Time")) + self["key_green"].setText(_("Set Time")) + + def createSetup(self): # This overrides the same class in Setup.py. + configList = [ + (_("End time"), self.dateTime, _("Select the time when this instant recording timer should end. Press LEFT/RIGHT to decrease/increase the time by a minute. Press PREV/NEXT to decrease/increase the time by an hour.")) + ] + self["config"].setList(configList) diff --git a/lib/python/Screens/EpgSelection.py b/lib/python/Screens/EpgSelection.py index 6e0139cc69b..2325f555eed 100644 --- a/lib/python/Screens/EpgSelection.py +++ b/lib/python/Screens/EpgSelection.py @@ -4,7 +4,6 @@ from RecordTimer import AFTEREVENT, RecordTimerEntry, parseEvent from ServiceReference import ServiceReference -from skin import getSkinFactor from Components.ActionMap import HelpableActionMap, HelpableNumberActionMap from Components.config import ConfigClock, config, configfile from Components.EpgList import EPG_TYPE_ENHANCED, EPG_TYPE_GRAPH, EPG_TYPE_INFOBAR, EPG_TYPE_INFOBARGRAPH, EPG_TYPE_MULTI, EPG_TYPE_SIMILAR, EPG_TYPE_SINGLE, EPG_TYPE_VERTICAL, EPGBouquetList, EPGList, MAX_TIMELINES, TimelineText @@ -16,13 +15,13 @@ from Components.Sources.StaticText import StaticText from Components.UsageConfig import preferredTimerPath from Screens.ChoiceBox import ChoiceBox +from Screens.DateTimeInput import EPGJumpTime from Screens.EventView import EventViewEPGSelect, EventViewSimple from Screens.HelpMenu import HelpableScreen from Screens.MessageBox import MessageBox from Screens.PictureInPicture import PictureInPicture from Screens.Screen import Screen from Screens.Setup import Setup -from Screens.TimeDateInput import TimeDateInput from Screens.TimerEdit import TimerSanityConflict from Screens.TimerEntry import InstantRecordTimerEntry, TimerEntry @@ -347,16 +346,16 @@ def __init__(self, session, service=None, zapFunc=None, eventid=None, bouquetCha self["bouquetokactions"].csel = self self["bouquetokactions"].setEnabled(False) self["input_actions"] = HelpableNumberActionMap(self, ["NumberActions"], { - "1": (self.keyNumberGlobal, _("Goto first channel")), - "2": (self.keyNumberGlobal, _("All events up")), - "3": (self.keyNumberGlobal, _("Goto last channel")), - "4": (self.keyNumberGlobal, _("Previous channel page")), - "0": (self.keyNumberGlobal, _("Goto current channel and now")), - "6": (self.keyNumberGlobal, _("Next channel page")), - "7": (self.keyNumberGlobal, _("Goto now")), - "8": (self.keyNumberGlobal, _("All events down")), - "9": (self.keyNumberGlobal, _("Goto Prime Time")), - "5": (self.keyNumberGlobal, _("Set Base Time")) + "1": (self.keyNumberGlobal, _("Goto first channel")), + "2": (self.keyNumberGlobal, _("All events up")), + "3": (self.keyNumberGlobal, _("Goto last channel")), + "4": (self.keyNumberGlobal, _("Previous channel page")), + "0": (self.keyNumberGlobal, _("Goto current channel and now")), + "6": (self.keyNumberGlobal, _("Next channel page")), + "7": (self.keyNumberGlobal, _("Goto now")), + "8": (self.keyNumberGlobal, _("All events down")), + "9": (self.keyNumberGlobal, _("Goto Prime Time")), + "5": (self.keyNumberGlobal, _("Set Base Time")) }, prio=-1, description=_("EPG Other Actions")) if self.type == EPG_TYPE_GRAPH: time_epoch = int(config.epgselection.graph_prevtimeperiod.value) @@ -864,41 +863,41 @@ def prevService(self): self.serviceChangeCB(-1, self) def enterDateTime(self): - global mepg_config_initialized - if self.type == EPG_TYPE_MULTI: - if not mepg_config_initialized: - config.misc.prev_mepg_time = ConfigClock(default=time()) - mepg_config_initialized = True - self.session.openWithCallback(self.onDateTimeInputClosed, TimeDateInput, config.misc.prev_mepg_time) - elif self.type == EPG_TYPE_GRAPH: - self.session.openWithCallback(self.onDateTimeInputClosed, TimeDateInput, config.epgselection.graph_prevtime) - elif self.type == EPG_TYPE_INFOBARGRAPH: - self.session.openWithCallback(self.onDateTimeInputClosed, TimeDateInput, config.epgselection.infobar_prevtime) - elif self.type == EPG_TYPE_VERTICAL: - self.session.openWithCallback(self.onDateTimeInputClosed, TimeDateInput, config.epgselection.vertical_prevtime) - - def onDateTimeInputClosed(self, ret): - if len(ret) > 1: - if ret[0]: - self.ask_time = ret[1] + def enterDateTimeCallback(result): + if len(result) > 1 and result[0]: + jumpTime = result[1] if self.type == EPG_TYPE_MULTI: - self["list"].fillMultiEPG(self.services, self.ask_time) - elif self.type == EPG_TYPE_GRAPH or self.type == EPG_TYPE_INFOBARGRAPH: + self["list"].fillMultiEPG(self.services, jumpTime) + elif self.type in (EPG_TYPE_GRAPH, EPG_TYPE_INFOBARGRAPH): if self.type == EPG_TYPE_GRAPH: - self.ask_time -= self.ask_time % (int(config.epgselection.graph_roundto.value) * 60) - elif self.type == EPG_TYPE_INFOBARGRAPH: - self.ask_time -= self.ask_time % (int(config.epgselection.infobar_roundto.value) * 60) - l = self["list"] - l.resetOffset() - l.fillGraphEPG(None, self.ask_time) + jumpTime -= jumpTime % (int(config.epgselection.graph_roundto.value) * 60) + else: + jumpTime -= jumpTime % (int(config.epgselection.infobar_roundto.value) * 60) + epgList = self["list"] + epgList.resetOffset() + epgList.fillGraphEPG(None, jumpTime) self.moveTimeLines(True) - elif EPG_TYPE_VERTICAL: - if self.ask_time > time(): + elif self.type == EPG_TYPE_VERTICAL: + if jumpTime > time(): self.updateVerticalEPG() else: - self.ask_time = -1 - if self.eventviewDialog and (self.type == EPG_TYPE_INFOBAR or self.type == EPG_TYPE_INFOBARGRAPH): - self.infoKeyPressed(True) + jumpTime = -1 + self.ask_time = jumpTime + if self.eventviewDialog and self.type in (EPG_TYPE_INFOBAR, EPG_TYPE_INFOBARGRAPH): + self.infoKeyPressed(True) + + if self.type == EPG_TYPE_GRAPH: + self.session.openWithCallback(enterDateTimeCallback, EPGJumpTime, config.epgselection.graph_prevtime, config.epg.histminutes.value) + elif self.type == EPG_TYPE_INFOBARGRAPH: + self.session.openWithCallback(enterDateTimeCallback, EPGJumpTime, config.epgselection.infobar_prevtime, config.epg.histminutes.value) + elif self.type == EPG_TYPE_MULTI: + global mepg_config_initialized + if not mepg_config_initialized: + config.misc.prev_mepg_time = ConfigClock(default=time()) + mepg_config_initialized = True + self.session.openWithCallback(enterDateTimeCallback, EPGJumpTime, config.misc.prev_mepg_time, 0) + elif self.type == EPG_TYPE_VERTICAL: + self.session.openWithCallback(enterDateTimeCallback, EPGJumpTime, config.epgselection.vertical_prevtime, config.epg.histminutes.value) def infoKeyPressed(self, eventviewopen=False): cur = self["list" + str(self.activeList)].getCurrent() @@ -1444,16 +1443,15 @@ def RecordTimerQuestion(self, manual=False): self.session.openWithCallback(self.finishedAdd, TimerEntry, newEntry) if title: - self.ChoiceBoxDialog = self.session.instantiateDialog(ChoiceBox, title=title, list=menu, keys=["red", "green", "yellow", "blue"], skin_name="RecordTimerQuestion") - serviceref = eServiceReference(str(self["list" + str(self.activeList)].getCurrent()[1])) - pos = self["list" + str(self.activeList)].getSelectionPosition(serviceref, self.activeList) - sf = getSkinFactor() - posx = max(self.instance.position().x() + pos[0] - self.ChoiceBoxDialog.instance.size().width() - 20 * sf, 0) - posy = self.instance.position().y() + pos[1] - posy += self["list" + str(self.activeList)].itemHeight - 2 * sf - if posy + self.ChoiceBoxDialog.instance.size().height() > 720 * sf: - posy -= self["list" + str(self.activeList)].itemHeight - 4 * sf + self.ChoiceBoxDialog.instance.size().height() - self.ChoiceBoxDialog.instance.move(ePoint(int(posx), int(posy))) + self.ChoiceBoxDialog = self.session.instantiateDialog(ChoiceBox, text=title, choiceList=menu, buttonList=["red", "green", "yellow", "blue"], skinName="RecordTimerQuestion") + serviceRef = eServiceReference(str(self[f"list{self.activeList}"].getCurrent()[1])) + pos = self[f"list{self.activeList}"].getSelectionPosition(serviceRef, self.activeList) + posX = max(self.instance.position().x() + pos[0] - self.ChoiceBoxDialog.instance.size().width(), 0) + posY = self.instance.position().y() + pos[1] + posY += self[f"list{self.activeList}"].itemHeight - 2 + if posY + self.ChoiceBoxDialog.instance.size().height() > 720: + posY -= self[f"list{self.activeList}"].itemHeight - 4 + self.ChoiceBoxDialog.instance.size().height() + self.ChoiceBoxDialog.instance.move(ePoint(int(posX), int(posY))) self.showChoiceBoxDialog() def recButtonPressed(self): @@ -1493,6 +1491,7 @@ def showChoiceBoxDialog(self): self["epgactions"].setEnabled(False) self["dialogactions"].setEnabled(True) self.ChoiceBoxDialog["actions"].execBegin() + self.ChoiceBoxDialog["navigationActions"].execBegin() self.ChoiceBoxDialog.show() if "input_actions" in self: self["input_actions"].setEnabled(False) @@ -1501,6 +1500,7 @@ def closeChoiceBoxDialog(self): self["dialogactions"].setEnabled(False) if self.ChoiceBoxDialog: self.ChoiceBoxDialog["actions"].execEnd() + self.ChoiceBoxDialog["navigationActions"].execEnd() self.session.deleteDialog(self.ChoiceBoxDialog) self["okactions"].setEnabled(True) if "epgcursoractions" in self: diff --git a/lib/python/Screens/InfoBarGenerics.py b/lib/python/Screens/InfoBarGenerics.py index 0b817a32dc5..9c534681531 100644 --- a/lib/python/Screens/InfoBarGenerics.py +++ b/lib/python/Screens/InfoBarGenerics.py @@ -36,6 +36,7 @@ from Plugins.Plugin import PluginDescriptor from Screens.ChannelSelection import ChannelSelection, PiPZapSelection, BouquetSelector, SilentBouquetSelector, EpgBouquetSelector, service_types_tv from Screens.ChoiceBox import ChoiceBox +from Screens.DateTimeInput import InstantRecordingEndTime from Screens.Dish import Dish from Screens.EpgSelection import EPGSelection from Screens.EventView import EventViewEPGSelect, EventViewSimple @@ -52,7 +53,6 @@ from Screens.Setup import Setup import Screens.Standby from Screens.Standby import Standby, TryQuitMainloop -from Screens.TimeDateInput import TimeDateInput from Screens.Timers import RecordTimerEdit, RecordTimerOverview from Screens.UnhandledKey import UnhandledKey from Tools import Notifications @@ -456,7 +456,7 @@ def __init__(self): # 3 = Long. # 4 = ASCII. def processKeyA(self, key, flag): # This function is called on every key press! - print("[InfoBarGenerics] Key '%s' (%s) %s." % (KEYIDNAMES.get(key, _("Unknown")), key, KEYFLAGS.get(flag, _("Unknown")))) + print(f"[InfoBarGenerics] Key '{KEYIDNAMES.get(key, _('Unknown'))}' ({key}) {KEYFLAGS.get(flag, _('Unknown'))}.") for callback in keyPressCallback: callback() if self.closeSecondInfoBar(key) and self.secondInfoBarScreen and self.secondInfoBarScreen.shown: @@ -3939,11 +3939,11 @@ def startInstantRecording(self, limitEvent=False): if recording.setAutoincreaseEnd(): self.session.nav.RecordTimer.record(recording) self.recording.append(recording) - self.session.open(MessageBox, _("Record time limited due to conflicting timer: %s") % f"\n{name_date}", MessageBox.TYPE_INFO) + self.session.open(MessageBox, _("Record time limited due to conflicting timer:%s") % f"\n\t'{name_date}'", MessageBox.TYPE_INFO) else: - self.session.open(MessageBox, _("Could not record due to conflicting timer: %s") % f"\n{name}", MessageBox.TYPE_INFO) + self.session.open(MessageBox, _("Could not record due to conflicting timer:%s") % f"\n\t'{name}'", MessageBox.TYPE_INFO) else: - self.session.open(MessageBox, _("Could not record due to invalid service: %s") % f"\n{serviceref}", MessageBox.TYPE_INFO) + self.session.open(MessageBox, _("Could not record due to invalid service:%s") % f"\n\t'{serviceref}'", MessageBox.TYPE_INFO) recording.autoincrease = False def startRecordingCurrentEvent(self): @@ -4008,40 +4008,36 @@ def recordQuestionCallback(self, answer): self.saveTimeshiftEventPopupActive = False def changeEndtime(self, entry): + def changeEndtimeCallback(result): + if len(result) > 1 and result[0]: + print(f"[InfoBarGenerics] Instant recording due to stop at {strftime('%F %T', localtime(result[1]))}.") + if recordingEntry.end != result[1]: + recordingEntry.autoincrease = False + recordingEntry.end = result[1] + recordingEntry.eventEnd = recordingEntry.end + recordingEntry.marginAfter = 0 # Why is this being done? + self.session.nav.RecordTimer.timeChanged(recordingEntry) + if entry is not None and entry >= 0: - self.selectedEntry = entry - self.endtime = ConfigClock(default=self.recording[self.selectedEntry].end) - dlg = self.session.openWithCallback(self.changeEndtimeCallback, TimeDateInput, self.endtime) - dlg.setTitle(_("Please change recording endtime")) + recordingEntry = self.recording[entry] + self.session.openWithCallback(changeEndtimeCallback, InstantRecordingEndTime, recordingEntry.eventEnd) - def changeEndtimeCallback(self, ret): - if len(ret) > 1 and ret[0]: - print(f"stop recording at {strftime('%F %T', localtime(ret[1]))}") + def changeDuration(self, entry): + def changeDurationCallback(value): entry = self.recording[self.selectedEntry] - if entry.end != ret[1]: - entry.autoincrease = False - entry.end = ret[1] - entry.eventEnd = entry.end - entry.marginAfter = 0 - self.session.nav.RecordTimer.timeChanged(self.recording[self.selectedEntry]) + if value is not None: + value = int(value.replace(" ", "") or "0") + if value: + entry.autoincrease = False + print(f"[InfoBarGenerics] Instant recording due to stop after {value} minutes.") + entry.end = int(time()) + 60 * value + entry.eventEnd = entry.end + entry.marginAfter = 0 + self.session.nav.RecordTimer.timeChanged(entry) - def changeDuration(self, entry): if entry is not None and entry >= 0: self.selectedEntry = entry - self.session.openWithCallback(self.changeDurationCallback, InputBox, title=_("How many minutes do you want to record?"), text="5 ", maxSize=True, type=Input.NUMBER) - - def changeDurationCallback(self, value): - entry = self.recording[self.selectedEntry] - if value is not None: - value = int(value.replace(" ", "") or "0") - if value: - entry.autoincrease = False - print(f"stop recording after {value} minutes.") - entry.end = int(time()) + 60 * value - entry.eventBegin = entry.begin - entry.eventEnd = entry.end - entry.marginAfter = 0 - self.session.nav.RecordTimer.timeChanged(entry) + self.session.openWithCallback(changeDurationCallback, InputBox, title=_("For how many minutes do you want to record?"), text="5 ", maxSize=True, type=Input.NUMBER) def isTimerRecordRunning(self): identical = timers = 0 @@ -4077,7 +4073,7 @@ def instantRecord(self, serviceRef=None): commonRecord = [] commonTimeshift = [] if self.isInstantRecordRunning(): - title = f'{_("A recording is currently running.")}\n{_("What do you want to do?")}' + title = f"{_('A recording is currently running.')}\n\n{_('What do you want to do?')}" choiceList = [ (_("Stop recording"), "stop") ] + commonRecord + [ @@ -4097,8 +4093,6 @@ def instantRecord(self, serviceRef=None): choiceList.append((_("Do not record"), "no")) if choiceList: self.session.openWithCallback(self.recordQuestionCallback, ChoiceBox, title=title, list=choiceList) - # else: - # return 0 class InfoBarAudioSelection: diff --git a/lib/python/Screens/TimeDateInput.py b/lib/python/Screens/TimeDateInput.py deleted file mode 100644 index 247ff6d41f2..00000000000 --- a/lib/python/Screens/TimeDateInput.py +++ /dev/null @@ -1,83 +0,0 @@ -from Screens.Screen import Screen -from Components.config import config, ConfigClock, ConfigDateTime, getConfigListEntry -from Components.ActionMap import NumberActionMap -from Components.ConfigList import ConfigListScreen -from Components.Sources.StaticText import StaticText -import time -import datetime - - -class TimeDateInput(Screen, ConfigListScreen): - def __init__(self, session, config_time=None, config_date=None): - Screen.__init__(self, session) - self.setTitle(_("Date/time input")) - self["key_red"] = StaticText(_("Cancel")) - self["key_green"] = StaticText(_("OK")) - - self.createConfig(config_date, config_time) - - self["actions"] = NumberActionMap(["SetupActions", "OkCancelActions", "ColorActions"], - { - "ok": self.keyGo, - "green": self.keyGo, - "save": self.keyGo, - "red": self.keyCancel, - "cancel": self.keyCancel, - }, -2) - - self.list = [] - ConfigListScreen.__init__(self, self.list) - self.createSetup(self["config"]) - - def createConfig(self, conf_date, conf_time): - self.save_mask = 0 - if conf_time: - self.save_mask |= 1 - else: - conf_time = ConfigClock(default=time.time()), - if conf_date: - self.save_mask |= 2 - else: - conf_date = ConfigDateTime(default=time.time(), formatstring=config.usage.date.dayfull.value, increment=86400) - self.timeinput_date = conf_date - self.timeinput_time = conf_time - - def createSetup(self, configlist): - self.list = [ - getConfigListEntry(_("Date"), self.timeinput_date), - getConfigListEntry(_("Time"), self.timeinput_time) - ] - configlist.list = self.list - configlist.l.setList(self.list) - - def keyPageDown(self): - sel = self["config"].getCurrent() - if sel and sel[1] == self.timeinput_time: - self.timeinput_time.decrement() - self["config"].invalidateCurrent() - - def keyPageUp(self): - sel = self["config"].getCurrent() - if sel and sel[1] == self.timeinput_time: - self.timeinput_time.increment() - self["config"].invalidateCurrent() - - def getTimestamp(self, date, mytime): - d = time.localtime(date) - dt = datetime.datetime(d.tm_year, d.tm_mon, d.tm_mday, mytime[0], mytime[1]) - return int(time.mktime(dt.timetuple())) - - def keyGo(self): - time = self.getTimestamp(self.timeinput_date.value, self.timeinput_time.value) - if self.save_mask & 1: - self.timeinput_time.save() - if self.save_mask & 2: - self.timeinput_date.save() - self.close((True, time)) - - def keyCancel(self): - if self.save_mask & 1: - self.timeinput_time.cancel() - if self.save_mask & 2: - self.timeinput_date.cancel() - self.close((False,))