1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
/*
* Copyright (C) 2022 Niels De Graef <nielsdegraef@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using Folks;
/**
* A {@link Chunk} that represents the birthday of a contact (similar to
* {@link Folks.BirthdayDetails}}.
*/
public class Contacts.BirthdayChunk : Chunk {
private DateTime? original_birthday = null;
public DateTime? birthday {
get { return this._birthday; }
set {
if (this.birthday == null && value == null)
return;
if (this.birthday != null && value != null && this.birthday.equal (value))
return;
bool was_empty = this.is_empty;
bool was_dirty = this.dirty;
this._birthday = (value != null)? value.to_utc () : null;
notify_property ("birthday");
if (was_empty != this.is_empty)
notify_property ("is-empty");
if (was_dirty != this.dirty)
notify_property ("dirty");
}
}
private DateTime? _birthday = null;
public override string property_name { get { return "birthday"; } }
public override bool is_empty { get { return this.birthday == null; } }
public override bool dirty {
get {
if (this.birthday != null && this.original_birthday != null)
return !this.birthday.equal (this.original_birthday);
return this.birthday != this.original_birthday;
}
}
construct {
if (persona != null) {
assert (persona is BirthdayDetails);
persona.bind_property ("birthday", this, "birthday");
this._birthday = ((BirthdayDetails) persona).birthday;
}
this.original_birthday = this.birthday;
}
public override Value? to_value () {
return this.birthday;
}
public override async void save_to_persona () throws GLib.Error
requires (this.persona is BirthdayDetails) {
yield ((BirthdayDetails) this.persona).change_birthday (this.birthday);
}
public bool is_today (DateTime now)
requires (this.birthday != null) {
int bd_m, bd_d, now_y, now_m, now_d;
_birthday.to_local().get_ymd (null, out bd_m, out bd_d);
now.get_ymd (out now_y, out now_m, out now_d);
return (bd_m == now_m && bd_d == now_d)
|| (is_leap_day (bd_m, bd_d) && is_birthday_of_leap_day_in_non_leap_year (now_y, now_m, now_d));
}
// February 28th is treated as birthday on non-leap years.
// This is consistent with the behaviour of evolution-data-server's Birthdays calendar:
// https://gitlab.gnome.org/GNOME/evolution-data-server/-/issues/88
private bool is_birthday_of_leap_day_in_non_leap_year (int now_y, int now_m, int now_d) {
return now_m == 2 && now_d == 28 && !is_leap_year (now_y);
}
private bool is_leap_year (int year) {
return ((DateYear) year).is_leap_year ();
}
private bool is_leap_day (int month, int day) {
return month == 2 && day == 29;
}
public override Variant? to_gvariant () {
if (this.birthday == null)
return null;
int year, month, day;
this.birthday.get_ymd (out year, out month, out day);
return new GLib.Variant ("(iii)", year, month, day);
}
public override void apply_gvariant (Variant variant,
bool mark_dirty = true)
requires (variant.get_type ().equal (new VariantType ("(iii)"))) {
int year, month, day;
variant.get ("(iii)", out year, out month, out day);
var bd = new DateTime.utc (year, month, day, 0, 0, 0.0);
if (!mark_dirty) {
this.original_birthday = bd;
}
this.birthday = bd;
}
}
|