Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an autoremember timer #331

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions app/common/setting-definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ let _VAL = { __proto__: null };
/// The default validator for bool values
let _vbool = (v)=>{ return ((typeof v === 'boolean')?v:undefined)};

/// The default validator for integer values
let _vint = (v)=>{
const num = Number(v);
if(isNaN(num) || (Math.trunc(num) != num)) {
return undefined;
}
return num;
};

// Booleans {{{2
_NAM.CFG_POPUP_ON_STARTUP = 'open-popup-on-chrome-startup';
_DEF[_NAM.CFG_POPUP_ON_STARTUP] = true;
Expand Down Expand Up @@ -165,6 +174,12 @@ _VAL[_NAM.CFGS_FAVICON_SOURCE] = (v)=>{
return (( v === FAVICON_SITE || v === FAVICON_CHROME || v === FAVICON_DDG ) ? v : undefined);
};

// #316. How often to autoremember. Empty or <= 0 == don't autosave
_NAM.CFGS_AUTOREMEMBER_MINUTES = 'autoremember-timer-minutes';
_DEF[_NAM.CFGS_AUTOREMEMBER_MINUTES] = '';
_VAL[_NAM.CFGS_AUTOREMEMBER_MINUTES] = _vint;


// }}}2

/// The default values for the configuration settings.
Expand Down Expand Up @@ -238,6 +253,33 @@ function getBoolSetting(setting_name, default_value = undefined)
}
} //getBoolSetting

/// Get an integer setting from the settings page.
/// @param setting_name A value in CFG_NAMES
/// @param default_value Optional default. If unspecified or
/// undefined, the default from CFG_DEFAULTS
/// is used.
function getIntSetting(setting_name, default_value = undefined)
{
if(typeof default_value === 'undefined' && setting_name in CFG_DEFAULTS) {
default_value = CFG_DEFAULTS[setting_name];
}

let locStorageValue = localStorage.getItem(SETTING_PREFIX + setting_name);

if ( locStorageValue === null ) { // nonexistent key
return default_value;
} else {
const str = String(locStorageValue);
let val = JSON.parse(locStorageValue); // stored with double-quotes
val = _vint(val);
if (typeof val === 'undefined') {
return default_value;
} else {
return val;
}
}
} //getIntSetting

/// Find out whether the given setting from the settings page exists.
/// @param setting_name A value in CFG_NAMES
function haveSetting(setting_name)
Expand Down Expand Up @@ -302,6 +344,7 @@ let me = {
getRaw: getRawSetting,
getString: getStringSetting,
getBool: getBoolSetting,
getInt: getIntSetting,
have: haveSetting,
set: setSetting,
setIfNonexistent: setSettingIfNonexistent,
Expand Down
20 changes: 19 additions & 1 deletion app/settings/manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,15 @@ setting_definitions.push(
"type": "checkbox",
"label": future_i18n('Prompt for confirmation before closing or deleting a tab that is currently playing audio (<i class="fa fa-music"></i>)'),
},
{
"tab": future_i18n("Behaviour"),
"group": future_i18n("Autoremember"),
"name": S.S_AUTOREMEMBER_MINUTES,
"type": "text",
"label": future_i18n('If this is an integer <tt>I</tt> &gt;= 0, automatically '
+ 'remember all open windows/tabs every <tt>I</tt> minutes. Refresh the '
+ 'TabFern window to apply changes to this option.'),
},

// Appearance
{
Expand Down Expand Up @@ -489,7 +498,16 @@ setting_definitions.push(
'group_html':true,
"type": "description",
"text": (
`<ul>
`<h4>TF needs developers!</h4>
<p>As you've noticed, my time to work on TabFern is limited 😅 .
If you are a JavaScript developer, could you contribute some code? I'm happy
to help you get started! If you aren't a JS dev, but know someone who is,
could you please pass the word? Much appreciated!
</p>
<ul>
<li>TabFern can now automatically mark windows as remembered on a timer.
Set the timer you want in ${settings} Behaviour ${gt} Autoremember
${issue(316)}.</li>
<li>The prompt for confirmation when closing audible tabs now applies to
individual tabs ${issue(306)}.</li>
<li>Bugfixes ${issue(322)}</li>
Expand Down
57 changes: 55 additions & 2 deletions app/win/main_tl.js
Original file line number Diff line number Diff line change
Expand Up @@ -4301,6 +4301,50 @@ function addEventListeners(done)
done();
} //addEventListeners

// Mark all windows as remembered
function rememberAll()
{
var modified = false;
L.log.info('Marking all windows as remembered')
try {
const root = T.treeobj.get_node($.jstree.root);
root.children.forEach( (kid_node_id, kid_idx)=>{
const val = D.windows.by_node_id(kid_node_id);
if(val && (val.keep !== K.WIN_KEEP)) {
modified = true;
M.remember(kid_node_id);
}
});

} catch(e) {
log.warn({'Failure when trying to auto-remember windows': e})
// But don't throw the error since we still want to save the tree.
}

if(modified) {
saveTree();
}
} //rememberAll

// Timer handler to call rememberAll() and set the next timer.
function autoRememberAll(minutes, only_start_timer = false)
{
if(!only_start_timer) {
rememberAll();
}

L.log.info(`Starting autoremember timer for ${minutes} minute(s)`);
window.setTimeout(()=>{autoRememberAll(minutes)}, minutes*60*1000);
} // autoRememberAll

function startAutoRememberTimerIfRequested(done) {
const minutes = S.getInt(S.S_AUTOREMEMBER_MINUTES, 0);
if(minutes > 0) {
autoRememberAll(minutes, true); // true => just start the timer
}
done();
} // startAutoRememberTimerIfRequested()

/// The last function to be called after all other initialization has
/// completed successfully.
function initTreeFinal(done)
Expand Down Expand Up @@ -4410,6 +4454,8 @@ function main()
};
//let spin_timer = window.setTimeout(spin_starter, 1000);

// --- Init steps ---

s.then(determine_devel_mode)
.then(basicInit)

Expand Down Expand Up @@ -4439,9 +4485,11 @@ function main()
})
.then(addOpenWindowsToTree)
.then(addEventListeners)
.then(initTreeFinal)
.then(initTreeFinal) // This needs to be the last real init step

.val(check_init_step_count) // This is a sanity check after initTreeFinal

.val(check_init_step_count)
// --- Post-init steps ---

// Stop the spinner, if it started
.val(()=>{
Expand All @@ -4450,6 +4498,11 @@ function main()
//clearTimeout(spin_timer);
})

// Start the autoremember timer now that all the state is consistent
.then(startAutoRememberTimerIfRequested)

// --- Error handling ---

.or((err)=>{
$(K.INIT_MSG_SEL).text(
$(K.INIT_MSG_SEL).text() + "\n" + err
Expand Down