Skip to content
Snippets Groups Projects
Unverified Commit c17b5f6f authored by Kali Kaneko's avatar Kali Kaneko
Browse files

[feat] re-implement donation reminders

first pass on giving functionality to the donation reminder
parent a18e61aa
No related branches found
No related tags found
No related merge requests found
......@@ -31,9 +31,14 @@ func Quit() {
}
//export ToggleDonate
func ToggleDonate() {
backend.ToggleDonate()
//export DonateAccepted
func DonateAccepted() {
backend.DonateAccepted()
}
//export DonateRejected
func DonateRejected() {
backend.DonateRejected()
}
//export SubscribeToEvent
......
#include <QTimer>
#include <QDebug>
#include <QDesktopServices>
#include <QUrl>
#include "handlers.h"
#include "lib/libgoshim.h"
......@@ -23,9 +25,19 @@ void Backend::unblock()
Unblock();
}
void Backend::toggleDonate()
void Backend::donateAccepted()
{
ToggleDonate();
DonateAccepted();
}
void Backend::donateRejected()
{
DonateRejected();
}
void Backend::openURL(QString link)
{
QDesktopServices::openUrl(QUrl(link));
}
void Backend::quit()
......
......@@ -33,7 +33,9 @@ public slots:
void switchOn();
void switchOff();
void unblock();
void toggleDonate();
void donateAccepted();
void donateRejected();
void openURL(QString link);
void quit();
};
......
......@@ -16,12 +16,13 @@ MessageDialog {
onAccepted: {
if (backend) {
backend.donateAccepted(true)
backend.openURL(ctx.donateURL)
backend.donateAccepted()
}
}
onRejected: {
if (backend) {
backend.donateAccepted(false)
backend.donateRejected()
}
}
}
......@@ -16,10 +16,9 @@ ApplicationWindow {
target: jsonModel
onDataChanged: {
ctx = JSON.parse(jsonModel.getJson());
if (ctx.donate == 'true') {
if (ctx.donateDialog == 'true') {
console.debug(jsonModel.getJson())
donate.visible = true
backend.toggleDonate()
}
}
}
......@@ -171,7 +170,9 @@ ApplicationWindow {
MenuItem {
text: qsTr("Donate...")
visible: true
//onTriggered: donate.open()
onTriggered: {
donate.visible = true
}
}
MenuItem {
......
......@@ -6,6 +6,7 @@ import (
"C"
"fmt"
"log"
"time"
"unsafe"
"0xacab.org/leap/bitmask-vpn/pkg/bitmask"
......@@ -23,18 +24,24 @@ func SwitchOff() {
}
func Unblock() {
//TODO
fmt.Println("unblock... [not implemented]")
}
func Quit() {
if ctx.Status != off {
go setStatus(stopping)
ctx.cfg.SetUserStoppedVPN(true)
stopVPN()
}
}
func ToggleDonate() {
toggleDonate()
func DonateAccepted() {
donateAccepted()
}
func DonateRejected() {
donateRejected()
}
func SubscribeToEvent(event string, f unsafe.Pointer) {
......@@ -42,21 +49,23 @@ func SubscribeToEvent(event string, f unsafe.Pointer) {
}
func InitializeBitmaskContext() {
pi := bitmask.GetConfiguredProvider()
p := bitmask.GetConfiguredProvider()
initOnce.Do(func() {
initializeContext(pi.Provider, pi.AppName)
initializeContext(
p.Provider, p.AppName)
})
go ctx.updateStatus()
/* DEBUG
timer := time.NewTimer(time.Second * 3)
go func() {
<-timer.C
fmt.Println("donate timer fired")
toggleDonate()
if needsDonationReminder() {
// wait a bit before launching reminder
timer := time.NewTimer(time.Minute * 5)
<-timer.C
showDonate()
}
}()
*/
}
func RefreshContext() *C.char {
......
......@@ -5,6 +5,7 @@ import (
"os"
"0xacab.org/leap/bitmask-vpn/pkg/bitmask"
"0xacab.org/leap/bitmask-vpn/pkg/config"
)
func initializeBitmask() {
......@@ -19,6 +20,7 @@ func initializeBitmask() {
log.Println("error: cannot initialize bitmask")
}
ctx.bm = b
ctx.cfg = config.ParseConfig()
}
func startVPN() {
......@@ -36,16 +38,25 @@ func stopVPN() {
}
}
func wantDonations() bool {
if config.AskForDonations == "true" {
return true
}
return false
}
// initializeContext initializes an empty connStatus and assigns it to the
// global ctx holder. This is expected to be called only once, so the public
// api uses the sync.Once primitive to call this.
func initializeContext(provider, appName string) {
var st status = off
ctx = &connectionCtx{
AppName: appName,
Provider: provider,
Donate: false,
Status: st,
AppName: appName,
Provider: provider,
DonateURL: config.DonateURL,
AskForDonations: wantDonations(),
DonateDialog: false,
Status: st,
}
go trigger(OnStatusChanged)
initializeBitmask()
......
package backend
import (
"log"
"time"
)
func needsDonationReminder() bool {
return ctx.cfg.NeedsDonationReminder()
}
func donateAccepted() {
stmut.Lock()
defer stmut.Unlock()
ctx.DonateDialog = false
log.Println("marking as donated")
ctx.cfg.SetDonated()
go trigger(OnStatusChanged)
}
func donateRejected() {
timer := time.NewTimer(time.Hour)
go func() {
<-timer.C
showDonate()
}()
}
func showDonate() {
stmut.Lock()
defer stmut.Unlock()
ctx.DonateDialog = true
ctx.cfg.SetLastReminded()
go trigger(OnStatusChanged)
}
......@@ -6,6 +6,7 @@ import (
"log"
"0xacab.org/leap/bitmask-vpn/pkg/bitmask"
"0xacab.org/leap/bitmask-vpn/pkg/config"
)
const (
......@@ -20,60 +21,20 @@ const (
// if we ever switch again to a provider-agnostic app, we should keep a map here.
var ctx *connectionCtx
// the status type reflects the current VPN status. Go code is responsible for updating
// it; the C gui just watches its changes and pulls its updates via the serialized
// context object.
type status int
const (
off status = iota
starting
on
stopping
failed
unknown
)
func (s status) String() string {
return [...]string{offStr, startingStr, onStr, stoppingStr, failedStr}[s]
}
func (s status) MarshalJSON() ([]byte, error) {
b := bytes.NewBufferString(`"`)
b.WriteString(s.String())
b.WriteString(`"`)
return b.Bytes(), nil
}
func (s status) fromString(st string) status {
switch st {
case offStr:
return off
case startingStr:
return starting
case onStr:
return on
case stoppingStr:
return stopping
case failedStr:
return failed
default:
return unknown
}
}
// The connectionCtx keeps the global state that is passed around to C-land. It
// also serves as the primary way of passing requests from the frontend to the
// Go-core, by letting the UI write some of these variables and processing
// them.
type connectionCtx struct {
AppName string `json:"appName"`
Provider string `json:"provider"`
Donate bool `json:"donate"`
Status status `json:"status"`
bm bitmask.Bitmask
AppName string `json:"appName"`
Provider string `json:"provider"`
AskForDonations bool `json:"askForDonations"`
DonateDialog bool `json:"donateDialog"`
DonateURL string `json:"donateURL"`
Status status `json:"status"`
bm bitmask.Bitmask
cfg *config.Config
}
func (c connectionCtx) toJson() ([]byte, error) {
......@@ -110,11 +71,47 @@ func setStatus(st status) {
go trigger(OnStatusChanged)
}
func toggleDonate() {
stmut.Lock()
defer stmut.Unlock()
ctx.Donate = !ctx.Donate
go trigger(OnStatusChanged)
// the status type reflects the current VPN status. Go code is responsible for updating
// it; the C gui just watches its changes and pulls its updates via the serialized
// context object.
type status int
const (
off status = iota
starting
on
stopping
failed
unknown
)
func (s status) String() string {
return [...]string{offStr, startingStr, onStr, stoppingStr, failedStr}[s]
}
func (s status) MarshalJSON() ([]byte, error) {
b := bytes.NewBufferString(`"`)
b.WriteString(s.String())
b.WriteString(`"`)
return b.Bytes(), nil
}
func (s status) fromString(st string) status {
switch st {
case offStr:
return off
case startingStr:
return starting
case onStr:
return on
case stoppingStr:
return stopping
case failedStr:
return failed
default:
return unknown
}
}
func setStatusFromStr(stStr string) {
......
......@@ -37,7 +37,7 @@ var (
// Config holds the configuration of the systray
type Config struct {
file struct {
LastNotification time.Time
LastReminded time.Time
Donated time.Time
SelectGateway bool
Obfs4 bool
......@@ -77,16 +77,16 @@ func (c *Config) SetUserStoppedVPN(vpnStopped bool) error {
return c.save()
}
func (c *Config) HasDonated() bool {
return c.file.Donated.Add(oneMonth).After(time.Now())
func (c *Config) NeedsDonationReminder() bool {
return !c.hasDonated() && c.file.LastReminded.Add(oneDay).Before(time.Now())
}
func (c *Config) NeedsNotification() bool {
return !c.HasDonated() && c.file.LastNotification.Add(oneDay).Before(time.Now())
func (c *Config) hasDonated() bool {
return c.file.Donated.Add(oneMonth).After(time.Now())
}
func (c *Config) SetNotification() error {
c.file.LastNotification = time.Now()
func (c *Config) SetLastReminded() error {
c.file.LastReminded = time.Now()
return c.save()
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment