mirror of
https://github.com/starovoid/rxing.git
synced 2026-07-27 21:02:35 +00:00
Calendar events ported not passing
This commit is contained in:
313
src/client/result/CalendarParsedResult.rs
Normal file
313
src/client/result/CalendarParsedResult.rs
Normal file
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// package com.google.zxing.client.result;
|
||||
|
||||
// import java.text.DateFormat;
|
||||
// import java.text.ParseException;
|
||||
// import java.text.SimpleDateFormat;
|
||||
// import java.util.Calendar;
|
||||
// import java.util.Date;
|
||||
// import java.util.GregorianCalendar;
|
||||
// import java.util.Locale;
|
||||
// import java.util.TimeZone;
|
||||
// import java.util.regex.Matcher;
|
||||
// import java.util.regex.Pattern;
|
||||
|
||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||
use regex::Regex;
|
||||
|
||||
use crate::exceptions::Exceptions;
|
||||
|
||||
use super::{
|
||||
maybe_append_multiple, maybe_append_string, ParsedRXingResult, ParsedRXingResultType,
|
||||
ResultParser,
|
||||
};
|
||||
|
||||
const RFC2445_DURATION: &'static str =
|
||||
"P(?:(\\d+)W)?(?:(\\d+)D)?(?:T(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+)S)?)?";
|
||||
const RFC2445_DURATION_FIELD_UNITS: [i64; 5] = [
|
||||
7 * 24 * 60 * 60 * 1000i64, // 1 week
|
||||
24 * 60 * 60 * 1000i64, // 1 day
|
||||
60 * 60 * 1000i64, // 1 hour
|
||||
60 * 1000i64, // 1 minute
|
||||
1000i64, // 1 second
|
||||
];
|
||||
|
||||
const DATE_TIME: &'static str = "[0-9]{8}(T[0-9]{6}Z?)?";
|
||||
|
||||
/**
|
||||
* Represents a parsed result that encodes a calendar event at a certain time, optionally
|
||||
* with attendees and a location.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
pub struct CalendarParsedRXingResult {
|
||||
summary: String,
|
||||
start: i64,
|
||||
startAllDay: bool,
|
||||
end: i64,
|
||||
endAllDay: bool,
|
||||
location: String,
|
||||
organizer: String,
|
||||
attendees: Vec<String>,
|
||||
description: String,
|
||||
latitude: f64,
|
||||
longitude: f64,
|
||||
}
|
||||
|
||||
impl ParsedRXingResult for CalendarParsedRXingResult {
|
||||
fn getType(&self) -> super::ParsedRXingResultType {
|
||||
ParsedRXingResultType::CALENDAR
|
||||
}
|
||||
|
||||
fn getDisplayRXingResult(&self) -> String {
|
||||
let mut result = String::with_capacity(100);
|
||||
maybe_append_string(&self.summary, &mut result);
|
||||
maybe_append_string(
|
||||
&Self::format_event(self.startAllDay, self.start),
|
||||
&mut result,
|
||||
);
|
||||
maybe_append_string(&Self::format_event(self.endAllDay, self.end), &mut result);
|
||||
maybe_append_string(&self.location, &mut result);
|
||||
maybe_append_string(&self.organizer, &mut result);
|
||||
maybe_append_multiple(&self.attendees, &mut result);
|
||||
maybe_append_string(&self.description, &mut result);
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl CalendarParsedRXingResult {
|
||||
pub fn new(
|
||||
summary: String,
|
||||
startString: String,
|
||||
endString: String,
|
||||
durationString: String,
|
||||
location: String,
|
||||
organizer: String,
|
||||
attendees: Vec<String>,
|
||||
description: String,
|
||||
latitude: f64,
|
||||
longitude: f64,
|
||||
) -> Result<Self, Exceptions> {
|
||||
let start = Self::parseDate(startString.clone())?;
|
||||
let end = if endString.is_empty() {
|
||||
let durationMS = Self::parseDurationMS(&durationString);
|
||||
if durationMS < 0i64 {
|
||||
-1i64
|
||||
} else {
|
||||
start + durationMS
|
||||
}
|
||||
} else {
|
||||
Self::parseDate(endString.clone())?
|
||||
};
|
||||
let startAllDay;
|
||||
let endAllDay;
|
||||
|
||||
// try {
|
||||
// this.start = parseDate(startString);
|
||||
// } catch (ParseException pe) {
|
||||
// throw new IllegalArgumentException(pe.toString());
|
||||
// }
|
||||
|
||||
// if (endString == null) {
|
||||
// long durationMS = parseDurationMS(durationString);
|
||||
// end = durationMS < 0L ? -1L : start + durationMS;
|
||||
// } else {
|
||||
// try {
|
||||
// this.end = parseDate(endString);
|
||||
// } catch (ParseException pe) {
|
||||
// throw new IllegalArgumentException(pe.toString());
|
||||
// }
|
||||
// }
|
||||
|
||||
startAllDay = startString.len() == 8;
|
||||
endAllDay = !endString.is_empty() && endString.len() == 8;
|
||||
|
||||
Ok(Self {
|
||||
summary,
|
||||
start,
|
||||
startAllDay,
|
||||
end,
|
||||
endAllDay,
|
||||
location,
|
||||
organizer,
|
||||
attendees,
|
||||
description,
|
||||
latitude,
|
||||
longitude,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string as a date. RFC 2445 allows the start and end fields to be of type DATE (e.g. 20081021)
|
||||
* or DATE-TIME (e.g. 20081021T123000 for local time, or 20081021T123000Z for UTC).
|
||||
*
|
||||
* @param when The string to parse
|
||||
* @throws ParseException if not able to parse as a date
|
||||
*/
|
||||
fn parseDate(when: String) -> Result<i64, Exceptions> {
|
||||
let date_time_regex = Regex::new(DATE_TIME).unwrap();
|
||||
if !date_time_regex.is_match(&when) {
|
||||
return Err(Exceptions::ParseException(when));
|
||||
}
|
||||
if when.len() == 8 {
|
||||
// Show only year/month/day
|
||||
let date_format_string = "%Y%m%d";
|
||||
// DateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.ENGLISH);
|
||||
// For dates without a time, for purposes of interacting with Android, the resulting timestamp
|
||||
// needs to be midnight of that day in GMT. See:
|
||||
// http://code.google.com/p/android/issues/detail?id=8330
|
||||
let dtm = DateTime::parse_from_str(&when, date_format_string).unwrap();
|
||||
let dtm = dtm.with_timezone(&Utc);
|
||||
|
||||
// format.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
// return format.parse(when).getTime();
|
||||
return Ok(dtm.timestamp());
|
||||
}
|
||||
// The when string can be local time, or UTC if it ends with a Z
|
||||
if when.len() == 16 && when.chars().nth(15).unwrap() == 'Z' {
|
||||
let milliseconds = Self::parseDateTimeString(&when[0..15]);
|
||||
// Calendar calendar = new GregorianCalendar();
|
||||
// // Account for time zone difference
|
||||
// milliseconds += calendar.get(Calendar.ZONE_OFFSET);
|
||||
// // Might need to correct for daylight savings time, but use target time since
|
||||
// // now might be in DST but not then, or vice versa
|
||||
// calendar.setTime(new Date(milliseconds));
|
||||
// return milliseconds + calendar.get(Calendar.DST_OFFSET);
|
||||
return milliseconds;
|
||||
}
|
||||
Self::parseDateTimeString(&when)
|
||||
}
|
||||
|
||||
fn format_event(allDay: bool, date: i64) -> String {
|
||||
if date < 0 {
|
||||
return "".to_owned();
|
||||
}
|
||||
let format_string = if allDay { "%F" } else { "%c" };
|
||||
// DateFormat format = allDay
|
||||
// ? DateFormat.getDateInstance(DateFormat.MEDIUM)
|
||||
// : DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM);
|
||||
// return format.format(date);
|
||||
NaiveDateTime::from_timestamp(date, 0)
|
||||
.format(format_string)
|
||||
.to_string()
|
||||
}
|
||||
|
||||
fn parseDurationMS(durationString: &str) -> i64 {
|
||||
if durationString.is_empty() {
|
||||
return -1;
|
||||
}
|
||||
let regex = Regex::new(RFC2445_DURATION).unwrap();
|
||||
if let Some(m) = regex.captures(durationString) {
|
||||
let mut durationMS = 0i64;
|
||||
for i in 0..RFC2445_DURATION_FIELD_UNITS.len() {
|
||||
// for (int i = 0; i < RFC2445_DURATION_FIELD_UNITS.length; i++) {
|
||||
let fieldValue = m.get(i + 1);
|
||||
if fieldValue.is_some() {
|
||||
let z = fieldValue.unwrap().as_str().parse::<i64>().unwrap();
|
||||
durationMS += RFC2445_DURATION_FIELD_UNITS[i] * z;
|
||||
}
|
||||
}
|
||||
durationMS
|
||||
} else {
|
||||
-1
|
||||
}
|
||||
// if (!m.matches()) {
|
||||
// return -1L;
|
||||
// }
|
||||
// long durationMS = 0L;
|
||||
// for (int i = 0; i < RFC2445_DURATION_FIELD_UNITS.length; i++) {
|
||||
// String fieldValue = m.group(i + 1);
|
||||
// if (fieldValue != null) {
|
||||
// durationMS += RFC2445_DURATION_FIELD_UNITS[i] * Integer.parseInt(fieldValue);
|
||||
// }
|
||||
// }
|
||||
// return durationMS;
|
||||
}
|
||||
|
||||
fn parseDateTimeString(dateTimeString: &str) -> Result<i64, Exceptions> {
|
||||
if let Ok(dtm) = DateTime::parse_from_str(dateTimeString, "%Y%m%dT%H%M%S") {
|
||||
Ok(dtm.timestamp())
|
||||
} else {
|
||||
Err(Exceptions::ParseException(format!(
|
||||
"Couldn't parse {}",
|
||||
dateTimeString
|
||||
)))
|
||||
}
|
||||
// DateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.ENGLISH);
|
||||
// return format.parse(dateTimeString).getTime();
|
||||
}
|
||||
|
||||
pub fn getSummary(&self) -> &String {
|
||||
&self.summary
|
||||
}
|
||||
|
||||
/**
|
||||
* @return start time
|
||||
* @see #getEndTimestamp()
|
||||
*/
|
||||
pub fn getStartTimestamp(&self) -> i64 {
|
||||
self.start
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if start time was specified as a whole day
|
||||
*/
|
||||
pub fn isStartAllDay(&self) -> bool {
|
||||
self.startAllDay
|
||||
}
|
||||
|
||||
/**
|
||||
* @return event end {@link Date}, or -1 if event has no duration
|
||||
* @see #getStartTimestamp()
|
||||
*/
|
||||
pub fn getEndTimestamp(&self) -> i64 {
|
||||
self.end
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if end time was specified as a whole day
|
||||
*/
|
||||
pub fn isEndAllDay(&self) -> bool {
|
||||
self.endAllDay
|
||||
}
|
||||
|
||||
pub fn getLocation(&self) -> &str {
|
||||
&self.location
|
||||
}
|
||||
|
||||
pub fn getOrganizer(&self) -> &str {
|
||||
&self.organizer
|
||||
}
|
||||
|
||||
pub fn getAttendees(&self) -> &Vec<String> {
|
||||
&self.attendees
|
||||
}
|
||||
|
||||
pub fn getDescription(&self) -> &str {
|
||||
&self.description
|
||||
}
|
||||
|
||||
pub fn getLatitude(&self) -> f64 {
|
||||
self.latitude
|
||||
}
|
||||
|
||||
pub fn getLongitude(&self) -> f64 {
|
||||
self.longitude
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user