changement de candidat à l'investissement

This commit is contained in:
2017-01-26 11:04:03 +01:00
parent 6dd06b123f
commit a2403b676b
351 changed files with 359 additions and 497 deletions

View File

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Accounts;
namespace BookAStar.Droid.Accounts
{
class YavscAccountAuthenticator : AbstractAccountAuthenticator
{
public YavscAccountAuthenticator(Context context): base(context)
{
}
public override Bundle AddAccount(AccountAuthenticatorResponse response, string accountType, string authTokenType, string[] requiredFeatures, Bundle options)
{
throw new NotImplementedException();
}
public override Bundle ConfirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options)
{
throw new NotImplementedException();
}
public override Bundle EditProperties(AccountAuthenticatorResponse response, string accountType)
{
throw new NotImplementedException();
}
public override Bundle GetAuthToken(AccountAuthenticatorResponse response, Account account, string authTokenType, Bundle options)
{
throw new NotImplementedException();
}
public override string GetAuthTokenLabel(string authTokenType)
{
throw new NotImplementedException();
}
public override Bundle HasFeatures(AccountAuthenticatorResponse response, Account account, string[] features)
{
throw new NotImplementedException();
}
public override Bundle UpdateCredentials(AccountAuthenticatorResponse response, Account account, string authTokenType, Bundle options)
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,19 @@
Any raw assets you want to be deployed with your application can be placed in
this directory (and child directories) and given a Build Action of "AndroidAsset".
These files will be deployed with you package and will be accessible using Android's
AssetManager, like this:
public class ReadAsset : Activity
{
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
InputStream input = Assets.Open ("my_asset.txt");
}
}
Additionally, some Android functions will automatically load asset files:
Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,69 @@
<!DOCTYPE html>
<html>
<head>
<title>Bubble Theme - Quill</title>
<meta charset="utf-8">
<link rel="stylesheet" href="quill.bubble.css" />
<style>
.standalone-container {
margin: 50px auto;
width: 720px;
}
#bubble-container {
height: 350px;
}
</style>
</head>
<body>
<div class="standalone-container">
<div id="bubble-container"></div>
</div>
<form><input type="hidden" name="md" id="md" />
<input id="btnSubmit" type="submit" value="Valider" class="ql-hidden"/></form>
<script type="text/javascript" src="quill.min.js"></script>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="showdown.js"></script>
<script type="text/javascript" src="to-markdown.js"></script>
<script type="text/javascript" src="md-helpers.js"></script>
<script type="text/javascript">
var toolbarOptions = [
['bold', 'italic', 'underline', 'strike'], // toggled buttons
['blockquote', 'code-block'],
[{ 'header': 1 }, { 'header': 2 }], // custom button values
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
[{ 'indent': '-1' }, { 'indent': '+1' }], // outdent/indent
['clean'] // remove formatting button
];
var quill = new Quill('#bubble-container', {
modules: {
toolbar: toolbarOptions
},
placeholder: 'Composez votre texte ...',
theme: 'bubble'
});
function getMD() {
return markdownize($('#bubble-container div.ql-editor').html())
}
quill.on('text-change', function (delta, oldDelta, source)
{
if (source === "user") {
$('#md').val(getMD());
$('#btnSubmit').removeClass('ql-hidden');
};
});
</script>
</body>
</html>

View File

@ -0,0 +1,388 @@
/*
* The MIT License
* Copyright (c) 2012 Matias Meno <m@tias.me>
*/
@-webkit-keyframes passing-through {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px); }
30%, 70% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px); }
100% {
opacity: 0;
-webkit-transform: translateY(-40px);
-moz-transform: translateY(-40px);
-ms-transform: translateY(-40px);
-o-transform: translateY(-40px);
transform: translateY(-40px); } }
@-moz-keyframes passing-through {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px); }
30%, 70% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px); }
100% {
opacity: 0;
-webkit-transform: translateY(-40px);
-moz-transform: translateY(-40px);
-ms-transform: translateY(-40px);
-o-transform: translateY(-40px);
transform: translateY(-40px); } }
@keyframes passing-through {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px); }
30%, 70% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px); }
100% {
opacity: 0;
-webkit-transform: translateY(-40px);
-moz-transform: translateY(-40px);
-ms-transform: translateY(-40px);
-o-transform: translateY(-40px);
transform: translateY(-40px); } }
@-webkit-keyframes slide-in {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px); }
30% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px); } }
@-moz-keyframes slide-in {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px); }
30% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px); } }
@keyframes slide-in {
0% {
opacity: 0;
-webkit-transform: translateY(40px);
-moz-transform: translateY(40px);
-ms-transform: translateY(40px);
-o-transform: translateY(40px);
transform: translateY(40px); }
30% {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
-o-transform: translateY(0px);
transform: translateY(0px); } }
@-webkit-keyframes pulse {
0% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1); }
10% {
-webkit-transform: scale(1.1);
-moz-transform: scale(1.1);
-ms-transform: scale(1.1);
-o-transform: scale(1.1);
transform: scale(1.1); }
20% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1); } }
@-moz-keyframes pulse {
0% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1); }
10% {
-webkit-transform: scale(1.1);
-moz-transform: scale(1.1);
-ms-transform: scale(1.1);
-o-transform: scale(1.1);
transform: scale(1.1); }
20% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1); } }
@keyframes pulse {
0% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1); }
10% {
-webkit-transform: scale(1.1);
-moz-transform: scale(1.1);
-ms-transform: scale(1.1);
-o-transform: scale(1.1);
transform: scale(1.1); }
20% {
-webkit-transform: scale(1);
-moz-transform: scale(1);
-ms-transform: scale(1);
-o-transform: scale(1);
transform: scale(1); } }
.dropzone, .dropzone * {
box-sizing: border-box; }
.dropzone {
min-height: 150px;
border: 2px solid rgba(0, 0, 0, 0.3);
background: white;
padding: 20px 20px; }
.dropzone.dz-clickable {
cursor: pointer; }
.dropzone.dz-clickable * {
cursor: default; }
.dropzone.dz-clickable .dz-message, .dropzone.dz-clickable .dz-message * {
cursor: pointer; }
.dropzone.dz-started .dz-message {
display: none; }
.dropzone.dz-drag-hover {
border-style: solid; }
.dropzone.dz-drag-hover .dz-message {
opacity: 0.5; }
.dropzone .dz-message {
text-align: center;
margin: 2em 0; }
.dropzone .dz-preview {
position: relative;
display: inline-block;
vertical-align: top;
margin: 16px;
min-height: 100px; }
.dropzone .dz-preview:hover {
z-index: 1000; }
.dropzone .dz-preview:hover .dz-details {
opacity: 1; }
.dropzone .dz-preview.dz-file-preview .dz-image {
border-radius: 20px;
background: #999;
background: linear-gradient(to bottom, #eee, #ddd); }
.dropzone .dz-preview.dz-file-preview .dz-details {
opacity: 1; }
.dropzone .dz-preview.dz-image-preview {
background: white; }
.dropzone .dz-preview.dz-image-preview .dz-details {
-webkit-transition: opacity 0.2s linear;
-moz-transition: opacity 0.2s linear;
-ms-transition: opacity 0.2s linear;
-o-transition: opacity 0.2s linear;
transition: opacity 0.2s linear; }
.dropzone .dz-preview .dz-remove {
font-size: 14px;
text-align: center;
display: block;
cursor: pointer;
border: none; }
.dropzone .dz-preview .dz-remove:hover {
text-decoration: underline; }
.dropzone .dz-preview:hover .dz-details {
opacity: 1; }
.dropzone .dz-preview .dz-details {
z-index: 20;
position: absolute;
top: 0;
left: 0;
opacity: 0;
font-size: 13px;
min-width: 100%;
max-width: 100%;
padding: 2em 1em;
text-align: center;
color: rgba(0, 0, 0, 0.9);
line-height: 150%; }
.dropzone .dz-preview .dz-details .dz-size {
margin-bottom: 1em;
font-size: 16px; }
.dropzone .dz-preview .dz-details .dz-filename {
white-space: nowrap; }
.dropzone .dz-preview .dz-details .dz-filename:hover span {
border: 1px solid rgba(200, 200, 200, 0.8);
background-color: rgba(255, 255, 255, 0.8); }
.dropzone .dz-preview .dz-details .dz-filename:not(:hover) {
overflow: hidden;
text-overflow: ellipsis; }
.dropzone .dz-preview .dz-details .dz-filename:not(:hover) span {
border: 1px solid transparent; }
.dropzone .dz-preview .dz-details .dz-filename span, .dropzone .dz-preview .dz-details .dz-size span {
background-color: rgba(255, 255, 255, 0.4);
padding: 0 0.4em;
border-radius: 3px; }
.dropzone .dz-preview:hover .dz-image img {
-webkit-transform: scale(1.05, 1.05);
-moz-transform: scale(1.05, 1.05);
-ms-transform: scale(1.05, 1.05);
-o-transform: scale(1.05, 1.05);
transform: scale(1.05, 1.05);
-webkit-filter: blur(8px);
filter: blur(8px); }
.dropzone .dz-preview .dz-image {
border-radius: 20px;
overflow: hidden;
width: 120px;
height: 120px;
position: relative;
display: block;
z-index: 10; }
.dropzone .dz-preview .dz-image img {
display: block; }
.dropzone .dz-preview.dz-success .dz-success-mark {
-webkit-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);
-moz-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);
-ms-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);
-o-animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);
animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); }
.dropzone .dz-preview.dz-error .dz-error-mark {
opacity: 1;
-webkit-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);
-moz-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);
-ms-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);
-o-animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);
animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); }
.dropzone .dz-preview .dz-success-mark, .dropzone .dz-preview .dz-error-mark {
pointer-events: none;
opacity: 0;
z-index: 500;
position: absolute;
display: block;
top: 50%;
left: 50%;
margin-left: -27px;
margin-top: -27px; }
.dropzone .dz-preview .dz-success-mark svg, .dropzone .dz-preview .dz-error-mark svg {
display: block;
width: 54px;
height: 54px; }
.dropzone .dz-preview.dz-processing .dz-progress {
opacity: 1;
-webkit-transition: all 0.2s linear;
-moz-transition: all 0.2s linear;
-ms-transition: all 0.2s linear;
-o-transition: all 0.2s linear;
transition: all 0.2s linear; }
.dropzone .dz-preview.dz-complete .dz-progress {
opacity: 0;
-webkit-transition: opacity 0.4s ease-in;
-moz-transition: opacity 0.4s ease-in;
-ms-transition: opacity 0.4s ease-in;
-o-transition: opacity 0.4s ease-in;
transition: opacity 0.4s ease-in; }
.dropzone .dz-preview:not(.dz-processing) .dz-progress {
-webkit-animation: pulse 6s ease infinite;
-moz-animation: pulse 6s ease infinite;
-ms-animation: pulse 6s ease infinite;
-o-animation: pulse 6s ease infinite;
animation: pulse 6s ease infinite; }
.dropzone .dz-preview .dz-progress {
opacity: 1;
z-index: 1000;
pointer-events: none;
position: absolute;
height: 16px;
left: 50%;
top: 50%;
margin-top: -8px;
width: 80px;
margin-left: -40px;
background: rgba(255, 255, 255, 0.9);
-webkit-transform: scale(1);
border-radius: 8px;
overflow: hidden; }
.dropzone .dz-preview .dz-progress .dz-upload {
background: #333;
background: linear-gradient(to bottom, #666, #444);
position: absolute;
top: 0;
left: 0;
bottom: 0;
width: 0;
-webkit-transition: width 300ms ease-in-out;
-moz-transition: width 300ms ease-in-out;
-ms-transition: width 300ms ease-in-out;
-o-transition: width 300ms ease-in-out;
transition: width 300ms ease-in-out; }
.dropzone .dz-preview.dz-error .dz-error-message {
display: block; }
.dropzone .dz-preview.dz-error:hover .dz-error-message {
opacity: 1;
pointer-events: auto; }
.dropzone .dz-preview .dz-error-message {
pointer-events: none;
z-index: 1000;
position: absolute;
display: block;
display: none;
opacity: 0;
-webkit-transition: opacity 0.3s ease;
-moz-transition: opacity 0.3s ease;
-ms-transition: opacity 0.3s ease;
-o-transition: opacity 0.3s ease;
transition: opacity 0.3s ease;
border-radius: 8px;
font-size: 13px;
top: 130px;
left: -10px;
width: 140px;
background: #be2626;
background: linear-gradient(to bottom, #be2626, #a92222);
padding: 0.5em 1.2em;
color: white; }
.dropzone .dz-preview .dz-error-message:after {
content: '';
position: absolute;
top: -6px;
left: 64px;
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 6px solid #be2626; }

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

File diff suppressed because one or more lines are too long

16617
ZicMoove/ZicMoove.Droid/Assets/jquery-ui.js vendored Normal file

File diff suppressed because it is too large Load Diff

9210
ZicMoove/ZicMoove.Droid/Assets/jquery.js vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,31 @@
var markdownize = function(content) {
if (!content) return '';
var html = content.split("\n").map($.trim).filter(function(line) {
return line != "" ;
}).join("\n");
return toMarkdown(html);
};
var htmlize = function(content) {
return converter.makeHtml(content);
};
var updateHtml = function(jView,content) {
if (markdownize(jView.html()) === content) {
return;
}
var html = htmlize(content);
jView.html(html);
};
var updateMD = function(id,content) {
if (!content) return jQuery('#'+id).val('') ;
var markdown = markdownize(content);
if (jQuery('#'+id).val() === markdown) {
return;
}
jQuery('#'+id).val( markdown );
};
var onMDModified = ( function (event, data) {
$('#Submit').addClass('success');
updateMD(this.attributes["for"].value, data.content);
});

View File

@ -0,0 +1 @@
.hljs{display:block;overflow-x:auto;padding:0.5em;background:#23241f}.hljs,.hljs-tag,.hljs-subst{color:#f8f8f2}.hljs-strong,.hljs-emphasis{color:#a8a8a2}.hljs-bullet,.hljs-quote,.hljs-number,.hljs-regexp,.hljs-literal,.hljs-link{color:#ae81ff}.hljs-code,.hljs-title,.hljs-section,.hljs-selector-class{color:#a6e22e}.hljs-strong{font-weight:bold}.hljs-emphasis{font-style:italic}.hljs-keyword,.hljs-selector-tag,.hljs-name,.hljs-attr{color:#f92672}.hljs-symbol,.hljs-attribute{color:#66d9ef}.hljs-params,.hljs-class .hljs-title{color:#f8f8f2}.hljs-string,.hljs-type,.hljs-built_in,.hljs-builtin-name,.hljs-selector-id,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-addition,.hljs-variable,.hljs-template-variable{color:#e6db74}.hljs-comment,.hljs-deletion,.hljs-meta{color:#75715e}

View File

@ -0,0 +1,845 @@
/*!
* Quill Editor v1.0.2
* https://quilljs.com/
* Copyright (c) 2014, Jason Chen
* Copyright (c) 2013, salesforce.com
*/
.ql-container {
box-sizing: border-box;
font-family: Helvetica, Arial, sans-serif;
font-size: 13px;
height: 100%;
margin: 0px;
position: relative;
}
.ql-clipboard {
left: -100000px;
height: 1px;
overflow-y: hidden;
position: absolute;
top: 50%;
}
.ql-clipboard p {
margin: 0;
padding: 0;
}
.ql-editor {
box-sizing: border-box;
cursor: text;
line-height: 1.42;
height: 100%;
outline: none;
overflow-y: auto;
padding: 12px 15px;
tab-size: 4;
-moz-tab-size: 4;
text-align: left;
white-space: pre-wrap;
word-wrap: break-word;
}
.ql-editor p,
.ql-editor ol,
.ql-editor ul,
.ql-editor pre,
.ql-editor blockquote,
.ql-editor h1,
.ql-editor h2,
.ql-editor h3,
.ql-editor h4,
.ql-editor h5,
.ql-editor h6 {
margin: 0;
padding: 0;
counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol,
.ql-editor ul {
padding-left: 1.5em;
}
.ql-editor ol > li,
.ql-editor ul > li {
list-style-type: none;
}
.ql-editor ul > li::before {
content: '\25CF';
}
.ql-editor li::before {
display: inline-block;
margin-right: 0.3em;
text-align: right;
white-space: nowrap;
width: 1.2em;
}
.ql-editor li:not(.ql-direction-rtl)::before {
margin-left: -1.5em;
}
.ql-editor ol li,
.ql-editor ul li {
padding-left: 1.5em;
}
.ql-editor ol li {
counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
counter-increment: list-num;
}
.ql-editor ol li:before {
content: counter(list-num, decimal) '. ';
}
.ql-editor ol li.ql-indent-1 {
counter-increment: list-1;
}
.ql-editor ol li.ql-indent-1:before {
content: counter(list-1, lower-alpha) '. ';
}
.ql-editor ol li.ql-indent-1 {
counter-reset: list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-2 {
counter-increment: list-2;
}
.ql-editor ol li.ql-indent-2:before {
content: counter(list-2, lower-roman) '. ';
}
.ql-editor ol li.ql-indent-2 {
counter-reset: list-3 list-4 list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-3 {
counter-increment: list-3;
}
.ql-editor ol li.ql-indent-3:before {
content: counter(list-3, decimal) '. ';
}
.ql-editor ol li.ql-indent-3 {
counter-reset: list-4 list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-4 {
counter-increment: list-4;
}
.ql-editor ol li.ql-indent-4:before {
content: counter(list-4, lower-alpha) '. ';
}
.ql-editor ol li.ql-indent-4 {
counter-reset: list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-5 {
counter-increment: list-5;
}
.ql-editor ol li.ql-indent-5:before {
content: counter(list-5, lower-roman) '. ';
}
.ql-editor ol li.ql-indent-5 {
counter-reset: list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-6 {
counter-increment: list-6;
}
.ql-editor ol li.ql-indent-6:before {
content: counter(list-6, decimal) '. ';
}
.ql-editor ol li.ql-indent-6 {
counter-reset: list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-7 {
counter-increment: list-7;
}
.ql-editor ol li.ql-indent-7:before {
content: counter(list-7, lower-alpha) '. ';
}
.ql-editor ol li.ql-indent-7 {
counter-reset: list-8 list-9;
}
.ql-editor ol li.ql-indent-8 {
counter-increment: list-8;
}
.ql-editor ol li.ql-indent-8:before {
content: counter(list-8, lower-roman) '. ';
}
.ql-editor ol li.ql-indent-8 {
counter-reset: list-9;
}
.ql-editor ol li.ql-indent-9 {
counter-increment: list-9;
}
.ql-editor ol li.ql-indent-9:before {
content: counter(list-9, decimal) '. ';
}
.ql-editor .ql-indent-1:not(.ql-direction-rtl) {
padding-left: 3em;
}
.ql-editor li.ql-indent-1:not(.ql-direction-rtl) {
padding-left: 4.5em;
}
.ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right {
padding-right: 3em;
}
.ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right {
padding-right: 4.5em;
}
.ql-editor .ql-indent-2:not(.ql-direction-rtl) {
padding-left: 6em;
}
.ql-editor li.ql-indent-2:not(.ql-direction-rtl) {
padding-left: 7.5em;
}
.ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right {
padding-right: 6em;
}
.ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right {
padding-right: 7.5em;
}
.ql-editor .ql-indent-3:not(.ql-direction-rtl) {
padding-left: 9em;
}
.ql-editor li.ql-indent-3:not(.ql-direction-rtl) {
padding-left: 10.5em;
}
.ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right {
padding-right: 9em;
}
.ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right {
padding-right: 10.5em;
}
.ql-editor .ql-indent-4:not(.ql-direction-rtl) {
padding-left: 12em;
}
.ql-editor li.ql-indent-4:not(.ql-direction-rtl) {
padding-left: 13.5em;
}
.ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right {
padding-right: 12em;
}
.ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right {
padding-right: 13.5em;
}
.ql-editor .ql-indent-5:not(.ql-direction-rtl) {
padding-left: 15em;
}
.ql-editor li.ql-indent-5:not(.ql-direction-rtl) {
padding-left: 16.5em;
}
.ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right {
padding-right: 15em;
}
.ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right {
padding-right: 16.5em;
}
.ql-editor .ql-indent-6:not(.ql-direction-rtl) {
padding-left: 18em;
}
.ql-editor li.ql-indent-6:not(.ql-direction-rtl) {
padding-left: 19.5em;
}
.ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right {
padding-right: 18em;
}
.ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right {
padding-right: 19.5em;
}
.ql-editor .ql-indent-7:not(.ql-direction-rtl) {
padding-left: 21em;
}
.ql-editor li.ql-indent-7:not(.ql-direction-rtl) {
padding-left: 22.5em;
}
.ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right {
padding-right: 21em;
}
.ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right {
padding-right: 22.5em;
}
.ql-editor .ql-indent-8:not(.ql-direction-rtl) {
padding-left: 24em;
}
.ql-editor li.ql-indent-8:not(.ql-direction-rtl) {
padding-left: 25.5em;
}
.ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right {
padding-right: 24em;
}
.ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right {
padding-right: 25.5em;
}
.ql-editor .ql-indent-9:not(.ql-direction-rtl) {
padding-left: 27em;
}
.ql-editor li.ql-indent-9:not(.ql-direction-rtl) {
padding-left: 28.5em;
}
.ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right {
padding-right: 27em;
}
.ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right {
padding-right: 28.5em;
}
.ql-editor .ql-video {
display: block;
max-width: 100%;
}
.ql-editor .ql-video.ql-align-center {
margin: 0 auto;
}
.ql-editor .ql-video.ql-align-right {
margin: 0 0 0 auto;
}
.ql-editor .ql-bg-black {
background-color: #000;
}
.ql-editor .ql-bg-red {
background-color: #e60000;
}
.ql-editor .ql-bg-orange {
background-color: #f90;
}
.ql-editor .ql-bg-yellow {
background-color: #ff0;
}
.ql-editor .ql-bg-green {
background-color: #008a00;
}
.ql-editor .ql-bg-blue {
background-color: #06c;
}
.ql-editor .ql-bg-purple {
background-color: #93f;
}
.ql-editor .ql-color-white {
color: #fff;
}
.ql-editor .ql-color-red {
color: #e60000;
}
.ql-editor .ql-color-orange {
color: #f90;
}
.ql-editor .ql-color-yellow {
color: #ff0;
}
.ql-editor .ql-color-green {
color: #008a00;
}
.ql-editor .ql-color-blue {
color: #06c;
}
.ql-editor .ql-color-purple {
color: #93f;
}
.ql-editor .ql-font-serif {
font-family: Georgia, Times New Roman, serif;
}
.ql-editor .ql-font-monospace {
font-family: Monaco, Courier New, monospace;
}
.ql-editor .ql-size-small {
font-size: 0.75em;
}
.ql-editor .ql-size-large {
font-size: 1.5em;
}
.ql-editor .ql-size-huge {
font-size: 2.5em;
}
.ql-editor .ql-direction-rtl {
direction: rtl;
text-align: inherit;
}
.ql-editor .ql-align-center {
text-align: center;
}
.ql-editor .ql-align-justify {
text-align: justify;
}
.ql-editor .ql-align-right {
text-align: right;
}
.ql-editor.ql-blank::before {
color: rgba(0,0,0,0.6);
content: attr(data-placeholder);
font-style: italic;
pointer-events: none;
position: absolute;
}
.ql-bubble.ql-toolbar:after,
.ql-bubble .ql-toolbar:after {
clear: both;
content: '';
display: table;
}
.ql-bubble.ql-toolbar button,
.ql-bubble .ql-toolbar button {
background: none;
border: none;
cursor: pointer;
display: inline-block;
float: left;
height: 24px;
outline: none;
padding: 3px 5px;
width: 28px;
}
.ql-bubble.ql-toolbar button svg,
.ql-bubble .ql-toolbar button svg {
float: left;
height: 100%;
}
.ql-bubble.ql-toolbar input.ql-image[type=file],
.ql-bubble .ql-toolbar input.ql-image[type=file] {
display: none;
}
.ql-bubble.ql-toolbar button:hover,
.ql-bubble .ql-toolbar button:hover,
.ql-bubble.ql-toolbar button.ql-active,
.ql-bubble .ql-toolbar button.ql-active,
.ql-bubble.ql-toolbar .ql-picker-label:hover,
.ql-bubble .ql-toolbar .ql-picker-label:hover,
.ql-bubble.ql-toolbar .ql-picker-label.ql-active,
.ql-bubble .ql-toolbar .ql-picker-label.ql-active,
.ql-bubble.ql-toolbar .ql-picker-item:hover,
.ql-bubble .ql-toolbar .ql-picker-item:hover,
.ql-bubble.ql-toolbar .ql-picker-item.ql-selected,
.ql-bubble .ql-toolbar .ql-picker-item.ql-selected {
color: #fff;
}
.ql-bubble.ql-toolbar button:hover .ql-fill,
.ql-bubble .ql-toolbar button:hover .ql-fill,
.ql-bubble.ql-toolbar button.ql-active .ql-fill,
.ql-bubble .ql-toolbar button.ql-active .ql-fill,
.ql-bubble.ql-toolbar .ql-picker-label:hover .ql-fill,
.ql-bubble .ql-toolbar .ql-picker-label:hover .ql-fill,
.ql-bubble.ql-toolbar .ql-picker-label.ql-active .ql-fill,
.ql-bubble .ql-toolbar .ql-picker-label.ql-active .ql-fill,
.ql-bubble.ql-toolbar .ql-picker-item:hover .ql-fill,
.ql-bubble .ql-toolbar .ql-picker-item:hover .ql-fill,
.ql-bubble.ql-toolbar .ql-picker-item.ql-selected .ql-fill,
.ql-bubble .ql-toolbar .ql-picker-item.ql-selected .ql-fill,
.ql-bubble.ql-toolbar button:hover .ql-stroke.ql-fill,
.ql-bubble .ql-toolbar button:hover .ql-stroke.ql-fill,
.ql-bubble.ql-toolbar button.ql-active .ql-stroke.ql-fill,
.ql-bubble .ql-toolbar button.ql-active .ql-stroke.ql-fill,
.ql-bubble.ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,
.ql-bubble .ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,
.ql-bubble.ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,
.ql-bubble .ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,
.ql-bubble.ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,
.ql-bubble .ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,
.ql-bubble.ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill,
.ql-bubble .ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill {
fill: #fff;
}
.ql-bubble.ql-toolbar button:hover .ql-stroke,
.ql-bubble .ql-toolbar button:hover .ql-stroke,
.ql-bubble.ql-toolbar button.ql-active .ql-stroke,
.ql-bubble .ql-toolbar button.ql-active .ql-stroke,
.ql-bubble.ql-toolbar .ql-picker-label:hover .ql-stroke,
.ql-bubble .ql-toolbar .ql-picker-label:hover .ql-stroke,
.ql-bubble.ql-toolbar .ql-picker-label.ql-active .ql-stroke,
.ql-bubble .ql-toolbar .ql-picker-label.ql-active .ql-stroke,
.ql-bubble.ql-toolbar .ql-picker-item:hover .ql-stroke,
.ql-bubble .ql-toolbar .ql-picker-item:hover .ql-stroke,
.ql-bubble.ql-toolbar .ql-picker-item.ql-selected .ql-stroke,
.ql-bubble .ql-toolbar .ql-picker-item.ql-selected .ql-stroke,
.ql-bubble.ql-toolbar button:hover .ql-stroke-mitter,
.ql-bubble .ql-toolbar button:hover .ql-stroke-mitter,
.ql-bubble.ql-toolbar button.ql-active .ql-stroke-mitter,
.ql-bubble .ql-toolbar button.ql-active .ql-stroke-mitter,
.ql-bubble.ql-toolbar .ql-picker-label:hover .ql-stroke-mitter,
.ql-bubble .ql-toolbar .ql-picker-label:hover .ql-stroke-mitter,
.ql-bubble.ql-toolbar .ql-picker-label.ql-active .ql-stroke-mitter,
.ql-bubble .ql-toolbar .ql-picker-label.ql-active .ql-stroke-mitter,
.ql-bubble.ql-toolbar .ql-picker-item:hover .ql-stroke-mitter,
.ql-bubble .ql-toolbar .ql-picker-item:hover .ql-stroke-mitter,
.ql-bubble.ql-toolbar .ql-picker-item.ql-selected .ql-stroke-mitter,
.ql-bubble .ql-toolbar .ql-picker-item.ql-selected .ql-stroke-mitter {
stroke: #fff;
}
.ql-bubble {
box-sizing: border-box;
}
.ql-bubble * {
box-sizing: border-box;
}
.ql-bubble .ql-hidden {
display: none;
}
.ql-bubble .ql-out-bottom,
.ql-bubble .ql-out-top {
visibility: hidden;
}
.ql-bubble .ql-tooltip {
position: absolute;
}
.ql-bubble .ql-tooltip a {
cursor: pointer;
text-decoration: none;
}
.ql-bubble .ql-formats {
display: inline-block;
vertical-align: middle;
}
.ql-bubble .ql-formats:after {
clear: both;
content: '';
display: table;
}
.ql-bubble .ql-toolbar.bubble,
.ql-bubble .ql-stroke {
fill: none;
stroke: #ccc;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 2;
}
.ql-bubble .ql-stroke-mitter {
fill: none;
stroke: #ccc;
stroke-mitterlimit: 10;
stroke-width: 2;
}
.ql-bubble .ql-fill,
.ql-bubble .ql-stroke.ql-fill {
fill: #ccc;
}
.ql-bubble .ql-empty {
fill: none;
}
.ql-bubble .ql-even {
fill-rule: evenodd;
}
.ql-bubble .ql-thin,
.ql-bubble .ql-stroke.ql-thin {
stroke-width: 1;
}
.ql-bubble .ql-transparent {
opacity: 0.4;
}
.ql-bubble .ql-direction svg:last-child {
display: none;
}
.ql-bubble .ql-direction.ql-active svg:last-child {
display: inline;
}
.ql-bubble .ql-direction.ql-active svg:first-child {
display: none;
}
.ql-bubble .ql-editor h1 {
font-size: 2em;
}
.ql-bubble .ql-editor h2 {
font-size: 1.5em;
}
.ql-bubble .ql-editor h3 {
font-size: 1.17em;
}
.ql-bubble .ql-editor h4 {
font-size: 1em;
}
.ql-bubble .ql-editor h5 {
font-size: 0.83em;
}
.ql-bubble .ql-editor h6 {
font-size: 0.67em;
}
.ql-bubble .ql-editor a {
text-decoration: underline;
}
.ql-bubble .ql-editor blockquote {
border-left: 4px solid #ccc;
margin-bottom: 5px;
margin-top: 5px;
padding-left: 16px;
}
.ql-bubble .ql-editor code,
.ql-bubble .ql-editor pre {
background-color: #f0f0f0;
border-radius: 3px;
}
.ql-bubble .ql-editor pre {
white-space: pre-wrap;
margin-bottom: 5px;
margin-top: 5px;
padding: 5px 10px;
}
.ql-bubble .ql-editor code {
font-size: 85%;
padding-bottom: 2px;
padding-top: 2px;
}
.ql-bubble .ql-editor code:before,
.ql-bubble .ql-editor code:after {
content: "\A0";
letter-spacing: -2px;
}
.ql-bubble .ql-editor pre.ql-syntax {
background-color: #23241f;
color: #f8f8f2;
overflow: visible;
}
.ql-bubble .ql-editor img {
max-width: 100%;
}
.ql-bubble .ql-picker {
color: #ccc;
display: inline-block;
float: left;
font-size: 14px;
font-weight: 500;
height: 24px;
position: relative;
vertical-align: middle;
}
.ql-bubble .ql-picker-label {
cursor: pointer;
display: inline-block;
height: 100%;
padding-left: 8px;
padding-right: 2px;
position: relative;
width: 100%;
}
.ql-bubble .ql-picker-label::before {
display: inline-block;
line-height: 22px;
}
.ql-bubble .ql-picker-options {
background-color: #444;
display: none;
min-width: 100%;
padding: 4px 8px;
position: absolute;
white-space: nowrap;
}
.ql-bubble .ql-picker-options .ql-picker-item {
cursor: pointer;
display: block;
padding-bottom: 5px;
padding-top: 5px;
}
.ql-bubble .ql-picker.ql-expanded .ql-picker-label {
color: #777;
z-index: 2;
}
.ql-bubble .ql-picker.ql-expanded .ql-picker-label .ql-fill {
fill: #777;
}
.ql-bubble .ql-picker.ql-expanded .ql-picker-label .ql-stroke {
stroke: #777;
}
.ql-bubble .ql-picker.ql-expanded .ql-picker-options {
display: block;
margin-top: -1px;
top: 100%;
z-index: 1;
}
.ql-bubble .ql-color-picker,
.ql-bubble .ql-icon-picker {
width: 28px;
}
.ql-bubble .ql-color-picker .ql-picker-label,
.ql-bubble .ql-icon-picker .ql-picker-label {
padding: 2px 4px;
}
.ql-bubble .ql-color-picker .ql-picker-label svg,
.ql-bubble .ql-icon-picker .ql-picker-label svg {
right: 4px;
}
.ql-bubble .ql-icon-picker .ql-picker-options {
padding: 4px 0px;
}
.ql-bubble .ql-icon-picker .ql-picker-item {
height: 24px;
width: 24px;
padding: 2px 4px;
}
.ql-bubble .ql-color-picker .ql-picker-options {
padding: 3px 5px;
width: 152px;
}
.ql-bubble .ql-color-picker .ql-picker-item {
border: 1px solid transparent;
float: left;
height: 16px;
margin: 2px;
padding: 0px;
width: 16px;
}
.ql-bubble .ql-color-picker .ql-picker-item.ql-primary-color {
margin-bottom: toolbarPadding;
}
.ql-bubble .ql-picker:not(.ql-color-picker):not(.ql-icon-picker) svg {
position: absolute;
margin-top: -9px;
right: 0;
top: 50%;
width: 18px;
}
.ql-bubble .ql-picker.ql-header .ql-picker-label[data-label]:not([data-label=''])::before,
.ql-bubble .ql-picker.ql-font .ql-picker-label[data-label]:not([data-label=''])::before,
.ql-bubble .ql-picker.ql-size .ql-picker-label[data-label]:not([data-label=''])::before,
.ql-bubble .ql-picker.ql-header .ql-picker-item[data-label]:not([data-label=''])::before,
.ql-bubble .ql-picker.ql-font .ql-picker-item[data-label]:not([data-label=''])::before,
.ql-bubble .ql-picker.ql-size .ql-picker-item[data-label]:not([data-label=''])::before {
content: attr(data-label);
}
.ql-bubble .ql-picker.ql-header {
width: 98px;
}
.ql-bubble .ql-picker.ql-header .ql-picker-label::before,
.ql-bubble .ql-picker.ql-header .ql-picker-item::before {
content: 'Normal';
}
.ql-bubble .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
content: 'Heading 1';
}
.ql-bubble .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
content: 'Heading 2';
}
.ql-bubble .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
content: 'Heading 3';
}
.ql-bubble .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
content: 'Heading 4';
}
.ql-bubble .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
content: 'Heading 5';
}
.ql-bubble .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
content: 'Heading 6';
}
.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
font-size: 2em;
}
.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
font-size: 1.5em;
}
.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
font-size: 1.17em;
}
.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
font-size: 1em;
}
.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
font-size: 0.83em;
}
.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
font-size: 0.67em;
}
.ql-bubble .ql-picker.ql-font {
width: 108px;
}
.ql-bubble .ql-picker.ql-font .ql-picker-label::before,
.ql-bubble .ql-picker.ql-font .ql-picker-item::before {
content: 'Sans Serif';
}
.ql-bubble .ql-picker.ql-font .ql-picker-label[data-value=serif]::before,
.ql-bubble .ql-picker.ql-font .ql-picker-item[data-value=serif]::before {
content: 'Serif';
}
.ql-bubble .ql-picker.ql-font .ql-picker-label[data-value=monospace]::before,
.ql-bubble .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before {
content: 'Monospace';
}
.ql-bubble .ql-picker.ql-font .ql-picker-item[data-value=serif]::before {
font-family: Georgia, Times New Roman, serif;
}
.ql-bubble .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before {
font-family: Monaco, Courier New, monospace;
}
.ql-bubble .ql-picker.ql-size {
width: 98px;
}
.ql-bubble .ql-picker.ql-size .ql-picker-label::before,
.ql-bubble .ql-picker.ql-size .ql-picker-item::before {
content: 'Normal';
}
.ql-bubble .ql-picker.ql-size .ql-picker-label[data-value=small]::before,
.ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=small]::before {
content: 'Small';
}
.ql-bubble .ql-picker.ql-size .ql-picker-label[data-value=large]::before,
.ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=large]::before {
content: 'Large';
}
.ql-bubble .ql-picker.ql-size .ql-picker-label[data-value=huge]::before,
.ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=huge]::before {
content: 'Huge';
}
.ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=small]::before {
font-size: 10px;
}
.ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=large]::before {
font-size: 18px;
}
.ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=huge]::before {
font-size: 32px;
}
.ql-bubble .ql-color-picker.ql-background .ql-picker-item {
background-color: #fff;
}
.ql-bubble .ql-color-picker.ql-color .ql-picker-item {
background-color: #000;
}
.ql-bubble .ql-toolbar .ql-formats {
margin: 8px 12px 8px 0px;
}
.ql-bubble .ql-toolbar .ql-formats:first-child {
margin-left: 12px;
}
.ql-bubble .ql-color-picker svg {
margin: 1px;
}
.ql-bubble .ql-color-picker .ql-picker-item.ql-selected,
.ql-bubble .ql-color-picker .ql-picker-item:hover {
border-color: #fff;
}
.ql-bubble .ql-tooltip {
background-color: #444;
border-radius: 25px;
color: #fff;
margin-top: 10px;
}
.ql-bubble .ql-tooltip-arrow {
border-bottom: 6px solid #444;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
content: " ";
display: block;
left: 50%;
margin-left: -6px;
position: absolute;
top: -6px;
}
.ql-bubble .ql-tooltip.ql-editing .ql-tooltip-editor {
display: block;
}
.ql-bubble .ql-tooltip.ql-editing .ql-formats {
visibility: hidden;
}
.ql-bubble .ql-tooltip-editor {
display: none;
}
.ql-bubble .ql-tooltip-editor input[type=text] {
background: transparent;
border: none;
color: #fff;
font-size: 13px;
height: 100%;
outline: none;
padding: 10px 20px;
position: absolute;
width: 100%;
}
.ql-bubble .ql-tooltip-editor a {
top: 10px;
position: absolute;
right: 20px;
}
.ql-bubble .ql-tooltip-editor a:before {
color: #ccc;
content: "\D7";
font-size: 16px;
font-weight: bold;
}

View File

@ -0,0 +1,359 @@
/*!
* Quill Editor v1.0.2
* https://quilljs.com/
* Copyright (c) 2014, Jason Chen
* Copyright (c) 2013, salesforce.com
*/
.ql-container {
box-sizing: border-box;
font-family: Helvetica, Arial, sans-serif;
font-size: 13px;
height: 100%;
margin: 0px;
position: relative;
}
.ql-clipboard {
left: -100000px;
height: 1px;
overflow-y: hidden;
position: absolute;
top: 50%;
}
.ql-clipboard p {
margin: 0;
padding: 0;
}
.ql-editor {
box-sizing: border-box;
cursor: text;
line-height: 1.42;
height: 100%;
outline: none;
overflow-y: auto;
padding: 12px 15px;
tab-size: 4;
-moz-tab-size: 4;
text-align: left;
white-space: pre-wrap;
word-wrap: break-word;
}
.ql-editor p,
.ql-editor ol,
.ql-editor ul,
.ql-editor pre,
.ql-editor blockquote,
.ql-editor h1,
.ql-editor h2,
.ql-editor h3,
.ql-editor h4,
.ql-editor h5,
.ql-editor h6 {
margin: 0;
padding: 0;
counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol,
.ql-editor ul {
padding-left: 1.5em;
}
.ql-editor ol > li,
.ql-editor ul > li {
list-style-type: none;
}
.ql-editor ul > li::before {
content: '\25CF';
}
.ql-editor li::before {
display: inline-block;
margin-right: 0.3em;
text-align: right;
white-space: nowrap;
width: 1.2em;
}
.ql-editor li:not(.ql-direction-rtl)::before {
margin-left: -1.5em;
}
.ql-editor ol li,
.ql-editor ul li {
padding-left: 1.5em;
}
.ql-editor ol li {
counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
counter-increment: list-num;
}
.ql-editor ol li:before {
content: counter(list-num, decimal) '. ';
}
.ql-editor ol li.ql-indent-1 {
counter-increment: list-1;
}
.ql-editor ol li.ql-indent-1:before {
content: counter(list-1, lower-alpha) '. ';
}
.ql-editor ol li.ql-indent-1 {
counter-reset: list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-2 {
counter-increment: list-2;
}
.ql-editor ol li.ql-indent-2:before {
content: counter(list-2, lower-roman) '. ';
}
.ql-editor ol li.ql-indent-2 {
counter-reset: list-3 list-4 list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-3 {
counter-increment: list-3;
}
.ql-editor ol li.ql-indent-3:before {
content: counter(list-3, decimal) '. ';
}
.ql-editor ol li.ql-indent-3 {
counter-reset: list-4 list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-4 {
counter-increment: list-4;
}
.ql-editor ol li.ql-indent-4:before {
content: counter(list-4, lower-alpha) '. ';
}
.ql-editor ol li.ql-indent-4 {
counter-reset: list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-5 {
counter-increment: list-5;
}
.ql-editor ol li.ql-indent-5:before {
content: counter(list-5, lower-roman) '. ';
}
.ql-editor ol li.ql-indent-5 {
counter-reset: list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-6 {
counter-increment: list-6;
}
.ql-editor ol li.ql-indent-6:before {
content: counter(list-6, decimal) '. ';
}
.ql-editor ol li.ql-indent-6 {
counter-reset: list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-7 {
counter-increment: list-7;
}
.ql-editor ol li.ql-indent-7:before {
content: counter(list-7, lower-alpha) '. ';
}
.ql-editor ol li.ql-indent-7 {
counter-reset: list-8 list-9;
}
.ql-editor ol li.ql-indent-8 {
counter-increment: list-8;
}
.ql-editor ol li.ql-indent-8:before {
content: counter(list-8, lower-roman) '. ';
}
.ql-editor ol li.ql-indent-8 {
counter-reset: list-9;
}
.ql-editor ol li.ql-indent-9 {
counter-increment: list-9;
}
.ql-editor ol li.ql-indent-9:before {
content: counter(list-9, decimal) '. ';
}
.ql-editor .ql-indent-1:not(.ql-direction-rtl) {
padding-left: 3em;
}
.ql-editor li.ql-indent-1:not(.ql-direction-rtl) {
padding-left: 4.5em;
}
.ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right {
padding-right: 3em;
}
.ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right {
padding-right: 4.5em;
}
.ql-editor .ql-indent-2:not(.ql-direction-rtl) {
padding-left: 6em;
}
.ql-editor li.ql-indent-2:not(.ql-direction-rtl) {
padding-left: 7.5em;
}
.ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right {
padding-right: 6em;
}
.ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right {
padding-right: 7.5em;
}
.ql-editor .ql-indent-3:not(.ql-direction-rtl) {
padding-left: 9em;
}
.ql-editor li.ql-indent-3:not(.ql-direction-rtl) {
padding-left: 10.5em;
}
.ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right {
padding-right: 9em;
}
.ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right {
padding-right: 10.5em;
}
.ql-editor .ql-indent-4:not(.ql-direction-rtl) {
padding-left: 12em;
}
.ql-editor li.ql-indent-4:not(.ql-direction-rtl) {
padding-left: 13.5em;
}
.ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right {
padding-right: 12em;
}
.ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right {
padding-right: 13.5em;
}
.ql-editor .ql-indent-5:not(.ql-direction-rtl) {
padding-left: 15em;
}
.ql-editor li.ql-indent-5:not(.ql-direction-rtl) {
padding-left: 16.5em;
}
.ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right {
padding-right: 15em;
}
.ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right {
padding-right: 16.5em;
}
.ql-editor .ql-indent-6:not(.ql-direction-rtl) {
padding-left: 18em;
}
.ql-editor li.ql-indent-6:not(.ql-direction-rtl) {
padding-left: 19.5em;
}
.ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right {
padding-right: 18em;
}
.ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right {
padding-right: 19.5em;
}
.ql-editor .ql-indent-7:not(.ql-direction-rtl) {
padding-left: 21em;
}
.ql-editor li.ql-indent-7:not(.ql-direction-rtl) {
padding-left: 22.5em;
}
.ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right {
padding-right: 21em;
}
.ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right {
padding-right: 22.5em;
}
.ql-editor .ql-indent-8:not(.ql-direction-rtl) {
padding-left: 24em;
}
.ql-editor li.ql-indent-8:not(.ql-direction-rtl) {
padding-left: 25.5em;
}
.ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right {
padding-right: 24em;
}
.ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right {
padding-right: 25.5em;
}
.ql-editor .ql-indent-9:not(.ql-direction-rtl) {
padding-left: 27em;
}
.ql-editor li.ql-indent-9:not(.ql-direction-rtl) {
padding-left: 28.5em;
}
.ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right {
padding-right: 27em;
}
.ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right {
padding-right: 28.5em;
}
.ql-editor .ql-video {
display: block;
max-width: 100%;
}
.ql-editor .ql-video.ql-align-center {
margin: 0 auto;
}
.ql-editor .ql-video.ql-align-right {
margin: 0 0 0 auto;
}
.ql-editor .ql-bg-black {
background-color: #000;
}
.ql-editor .ql-bg-red {
background-color: #e60000;
}
.ql-editor .ql-bg-orange {
background-color: #f90;
}
.ql-editor .ql-bg-yellow {
background-color: #ff0;
}
.ql-editor .ql-bg-green {
background-color: #008a00;
}
.ql-editor .ql-bg-blue {
background-color: #06c;
}
.ql-editor .ql-bg-purple {
background-color: #93f;
}
.ql-editor .ql-color-white {
color: #fff;
}
.ql-editor .ql-color-red {
color: #e60000;
}
.ql-editor .ql-color-orange {
color: #f90;
}
.ql-editor .ql-color-yellow {
color: #ff0;
}
.ql-editor .ql-color-green {
color: #008a00;
}
.ql-editor .ql-color-blue {
color: #06c;
}
.ql-editor .ql-color-purple {
color: #93f;
}
.ql-editor .ql-font-serif {
font-family: Georgia, Times New Roman, serif;
}
.ql-editor .ql-font-monospace {
font-family: Monaco, Courier New, monospace;
}
.ql-editor .ql-size-small {
font-size: 0.75em;
}
.ql-editor .ql-size-large {
font-size: 1.5em;
}
.ql-editor .ql-size-huge {
font-size: 2.5em;
}
.ql-editor .ql-direction-rtl {
direction: rtl;
text-align: inherit;
}
.ql-editor .ql-align-center {
text-align: center;
}
.ql-editor .ql-align-justify {
text-align: justify;
}
.ql-editor .ql-align-right {
text-align: right;
}
.ql-editor.ql-blank::before {
color: rgba(0,0,0,0.6);
content: attr(data-placeholder);
font-style: italic;
pointer-events: none;
position: absolute;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,883 @@
/*!
* Quill Editor v1.0.2
* https://quilljs.com/
* Copyright (c) 2014, Jason Chen
* Copyright (c) 2013, salesforce.com
*/
.ql-container {
box-sizing: border-box;
font-family: Helvetica, Arial, sans-serif;
font-size: 13px;
height: 100%;
margin: 0px;
position: relative;
}
.ql-clipboard {
left: -100000px;
height: 1px;
overflow-y: hidden;
position: absolute;
top: 50%;
}
.ql-clipboard p {
margin: 0;
padding: 0;
}
.ql-editor {
box-sizing: border-box;
cursor: text;
line-height: 1.42;
height: 100%;
outline: none;
overflow-y: auto;
padding: 12px 15px;
tab-size: 4;
-moz-tab-size: 4;
text-align: left;
white-space: pre-wrap;
word-wrap: break-word;
}
.ql-editor p,
.ql-editor ol,
.ql-editor ul,
.ql-editor pre,
.ql-editor blockquote,
.ql-editor h1,
.ql-editor h2,
.ql-editor h3,
.ql-editor h4,
.ql-editor h5,
.ql-editor h6 {
margin: 0;
padding: 0;
counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol,
.ql-editor ul {
padding-left: 1.5em;
}
.ql-editor ol > li,
.ql-editor ul > li {
list-style-type: none;
}
.ql-editor ul > li::before {
content: '\25CF';
}
.ql-editor li::before {
display: inline-block;
margin-right: 0.3em;
text-align: right;
white-space: nowrap;
width: 1.2em;
}
.ql-editor li:not(.ql-direction-rtl)::before {
margin-left: -1.5em;
}
.ql-editor ol li,
.ql-editor ul li {
padding-left: 1.5em;
}
.ql-editor ol li {
counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
counter-increment: list-num;
}
.ql-editor ol li:before {
content: counter(list-num, decimal) '. ';
}
.ql-editor ol li.ql-indent-1 {
counter-increment: list-1;
}
.ql-editor ol li.ql-indent-1:before {
content: counter(list-1, lower-alpha) '. ';
}
.ql-editor ol li.ql-indent-1 {
counter-reset: list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-2 {
counter-increment: list-2;
}
.ql-editor ol li.ql-indent-2:before {
content: counter(list-2, lower-roman) '. ';
}
.ql-editor ol li.ql-indent-2 {
counter-reset: list-3 list-4 list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-3 {
counter-increment: list-3;
}
.ql-editor ol li.ql-indent-3:before {
content: counter(list-3, decimal) '. ';
}
.ql-editor ol li.ql-indent-3 {
counter-reset: list-4 list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-4 {
counter-increment: list-4;
}
.ql-editor ol li.ql-indent-4:before {
content: counter(list-4, lower-alpha) '. ';
}
.ql-editor ol li.ql-indent-4 {
counter-reset: list-5 list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-5 {
counter-increment: list-5;
}
.ql-editor ol li.ql-indent-5:before {
content: counter(list-5, lower-roman) '. ';
}
.ql-editor ol li.ql-indent-5 {
counter-reset: list-6 list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-6 {
counter-increment: list-6;
}
.ql-editor ol li.ql-indent-6:before {
content: counter(list-6, decimal) '. ';
}
.ql-editor ol li.ql-indent-6 {
counter-reset: list-7 list-8 list-9;
}
.ql-editor ol li.ql-indent-7 {
counter-increment: list-7;
}
.ql-editor ol li.ql-indent-7:before {
content: counter(list-7, lower-alpha) '. ';
}
.ql-editor ol li.ql-indent-7 {
counter-reset: list-8 list-9;
}
.ql-editor ol li.ql-indent-8 {
counter-increment: list-8;
}
.ql-editor ol li.ql-indent-8:before {
content: counter(list-8, lower-roman) '. ';
}
.ql-editor ol li.ql-indent-8 {
counter-reset: list-9;
}
.ql-editor ol li.ql-indent-9 {
counter-increment: list-9;
}
.ql-editor ol li.ql-indent-9:before {
content: counter(list-9, decimal) '. ';
}
.ql-editor .ql-indent-1:not(.ql-direction-rtl) {
padding-left: 3em;
}
.ql-editor li.ql-indent-1:not(.ql-direction-rtl) {
padding-left: 4.5em;
}
.ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right {
padding-right: 3em;
}
.ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right {
padding-right: 4.5em;
}
.ql-editor .ql-indent-2:not(.ql-direction-rtl) {
padding-left: 6em;
}
.ql-editor li.ql-indent-2:not(.ql-direction-rtl) {
padding-left: 7.5em;
}
.ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right {
padding-right: 6em;
}
.ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right {
padding-right: 7.5em;
}
.ql-editor .ql-indent-3:not(.ql-direction-rtl) {
padding-left: 9em;
}
.ql-editor li.ql-indent-3:not(.ql-direction-rtl) {
padding-left: 10.5em;
}
.ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right {
padding-right: 9em;
}
.ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right {
padding-right: 10.5em;
}
.ql-editor .ql-indent-4:not(.ql-direction-rtl) {
padding-left: 12em;
}
.ql-editor li.ql-indent-4:not(.ql-direction-rtl) {
padding-left: 13.5em;
}
.ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right {
padding-right: 12em;
}
.ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right {
padding-right: 13.5em;
}
.ql-editor .ql-indent-5:not(.ql-direction-rtl) {
padding-left: 15em;
}
.ql-editor li.ql-indent-5:not(.ql-direction-rtl) {
padding-left: 16.5em;
}
.ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right {
padding-right: 15em;
}
.ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right {
padding-right: 16.5em;
}
.ql-editor .ql-indent-6:not(.ql-direction-rtl) {
padding-left: 18em;
}
.ql-editor li.ql-indent-6:not(.ql-direction-rtl) {
padding-left: 19.5em;
}
.ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right {
padding-right: 18em;
}
.ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right {
padding-right: 19.5em;
}
.ql-editor .ql-indent-7:not(.ql-direction-rtl) {
padding-left: 21em;
}
.ql-editor li.ql-indent-7:not(.ql-direction-rtl) {
padding-left: 22.5em;
}
.ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right {
padding-right: 21em;
}
.ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right {
padding-right: 22.5em;
}
.ql-editor .ql-indent-8:not(.ql-direction-rtl) {
padding-left: 24em;
}
.ql-editor li.ql-indent-8:not(.ql-direction-rtl) {
padding-left: 25.5em;
}
.ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right {
padding-right: 24em;
}
.ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right {
padding-right: 25.5em;
}
.ql-editor .ql-indent-9:not(.ql-direction-rtl) {
padding-left: 27em;
}
.ql-editor li.ql-indent-9:not(.ql-direction-rtl) {
padding-left: 28.5em;
}
.ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right {
padding-right: 27em;
}
.ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right {
padding-right: 28.5em;
}
.ql-editor .ql-video {
display: block;
max-width: 100%;
}
.ql-editor .ql-video.ql-align-center {
margin: 0 auto;
}
.ql-editor .ql-video.ql-align-right {
margin: 0 0 0 auto;
}
.ql-editor .ql-bg-black {
background-color: #000;
}
.ql-editor .ql-bg-red {
background-color: #e60000;
}
.ql-editor .ql-bg-orange {
background-color: #f90;
}
.ql-editor .ql-bg-yellow {
background-color: #ff0;
}
.ql-editor .ql-bg-green {
background-color: #008a00;
}
.ql-editor .ql-bg-blue {
background-color: #06c;
}
.ql-editor .ql-bg-purple {
background-color: #93f;
}
.ql-editor .ql-color-white {
color: #fff;
}
.ql-editor .ql-color-red {
color: #e60000;
}
.ql-editor .ql-color-orange {
color: #f90;
}
.ql-editor .ql-color-yellow {
color: #ff0;
}
.ql-editor .ql-color-green {
color: #008a00;
}
.ql-editor .ql-color-blue {
color: #06c;
}
.ql-editor .ql-color-purple {
color: #93f;
}
.ql-editor .ql-font-serif {
font-family: Georgia, Times New Roman, serif;
}
.ql-editor .ql-font-monospace {
font-family: Monaco, Courier New, monospace;
}
.ql-editor .ql-size-small {
font-size: 0.75em;
}
.ql-editor .ql-size-large {
font-size: 1.5em;
}
.ql-editor .ql-size-huge {
font-size: 2.5em;
}
.ql-editor .ql-direction-rtl {
direction: rtl;
text-align: inherit;
}
.ql-editor .ql-align-center {
text-align: center;
}
.ql-editor .ql-align-justify {
text-align: justify;
}
.ql-editor .ql-align-right {
text-align: right;
}
.ql-editor.ql-blank::before {
color: rgba(0,0,0,0.6);
content: attr(data-placeholder);
font-style: italic;
pointer-events: none;
position: absolute;
}
.ql-snow.ql-toolbar:after,
.ql-snow .ql-toolbar:after {
clear: both;
content: '';
display: table;
}
.ql-snow.ql-toolbar button,
.ql-snow .ql-toolbar button {
background: none;
border: none;
cursor: pointer;
display: inline-block;
float: left;
height: 24px;
outline: none;
padding: 3px 5px;
width: 28px;
}
.ql-snow.ql-toolbar button svg,
.ql-snow .ql-toolbar button svg {
float: left;
height: 100%;
}
.ql-snow.ql-toolbar input.ql-image[type=file],
.ql-snow .ql-toolbar input.ql-image[type=file] {
display: none;
}
.ql-snow.ql-toolbar button:hover,
.ql-snow .ql-toolbar button:hover,
.ql-snow.ql-toolbar button.ql-active,
.ql-snow .ql-toolbar button.ql-active,
.ql-snow.ql-toolbar .ql-picker-label:hover,
.ql-snow .ql-toolbar .ql-picker-label:hover,
.ql-snow.ql-toolbar .ql-picker-label.ql-active,
.ql-snow .ql-toolbar .ql-picker-label.ql-active,
.ql-snow.ql-toolbar .ql-picker-item:hover,
.ql-snow .ql-toolbar .ql-picker-item:hover,
.ql-snow.ql-toolbar .ql-picker-item.ql-selected,
.ql-snow .ql-toolbar .ql-picker-item.ql-selected {
color: #06c;
}
.ql-snow.ql-toolbar button:hover .ql-fill,
.ql-snow .ql-toolbar button:hover .ql-fill,
.ql-snow.ql-toolbar button.ql-active .ql-fill,
.ql-snow .ql-toolbar button.ql-active .ql-fill,
.ql-snow.ql-toolbar .ql-picker-label:hover .ql-fill,
.ql-snow .ql-toolbar .ql-picker-label:hover .ql-fill,
.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-fill,
.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-fill,
.ql-snow.ql-toolbar .ql-picker-item:hover .ql-fill,
.ql-snow .ql-toolbar .ql-picker-item:hover .ql-fill,
.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-fill,
.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-fill,
.ql-snow.ql-toolbar button:hover .ql-stroke.ql-fill,
.ql-snow .ql-toolbar button:hover .ql-stroke.ql-fill,
.ql-snow.ql-toolbar button.ql-active .ql-stroke.ql-fill,
.ql-snow .ql-toolbar button.ql-active .ql-stroke.ql-fill,
.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,
.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,
.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,
.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,
.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,
.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,
.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill,
.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill {
fill: #06c;
}
.ql-snow.ql-toolbar button:hover .ql-stroke,
.ql-snow .ql-toolbar button:hover .ql-stroke,
.ql-snow.ql-toolbar button.ql-active .ql-stroke,
.ql-snow .ql-toolbar button.ql-active .ql-stroke,
.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke,
.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke,
.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke,
.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke,
.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke,
.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke,
.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke,
.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke,
.ql-snow.ql-toolbar button:hover .ql-stroke-mitter,
.ql-snow .ql-toolbar button:hover .ql-stroke-mitter,
.ql-snow.ql-toolbar button.ql-active .ql-stroke-mitter,
.ql-snow .ql-toolbar button.ql-active .ql-stroke-mitter,
.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke-mitter,
.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke-mitter,
.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke-mitter,
.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke-mitter,
.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke-mitter,
.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke-mitter,
.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke-mitter,
.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke-mitter {
stroke: #06c;
}
.ql-snow {
box-sizing: border-box;
}
.ql-snow * {
box-sizing: border-box;
}
.ql-snow .ql-hidden {
display: none;
}
.ql-snow .ql-out-bottom,
.ql-snow .ql-out-top {
visibility: hidden;
}
.ql-snow .ql-tooltip {
position: absolute;
}
.ql-snow .ql-tooltip a {
cursor: pointer;
text-decoration: none;
}
.ql-snow .ql-formats {
display: inline-block;
vertical-align: middle;
}
.ql-snow .ql-formats:after {
clear: both;
content: '';
display: table;
}
.ql-snow .ql-toolbar.snow,
.ql-snow .ql-stroke {
fill: none;
stroke: #444;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 2;
}
.ql-snow .ql-stroke-mitter {
fill: none;
stroke: #444;
stroke-mitterlimit: 10;
stroke-width: 2;
}
.ql-snow .ql-fill,
.ql-snow .ql-stroke.ql-fill {
fill: #444;
}
.ql-snow .ql-empty {
fill: none;
}
.ql-snow .ql-even {
fill-rule: evenodd;
}
.ql-snow .ql-thin,
.ql-snow .ql-stroke.ql-thin {
stroke-width: 1;
}
.ql-snow .ql-transparent {
opacity: 0.4;
}
.ql-snow .ql-direction svg:last-child {
display: none;
}
.ql-snow .ql-direction.ql-active svg:last-child {
display: inline;
}
.ql-snow .ql-direction.ql-active svg:first-child {
display: none;
}
.ql-snow .ql-editor h1 {
font-size: 2em;
}
.ql-snow .ql-editor h2 {
font-size: 1.5em;
}
.ql-snow .ql-editor h3 {
font-size: 1.17em;
}
.ql-snow .ql-editor h4 {
font-size: 1em;
}
.ql-snow .ql-editor h5 {
font-size: 0.83em;
}
.ql-snow .ql-editor h6 {
font-size: 0.67em;
}
.ql-snow .ql-editor a {
text-decoration: underline;
}
.ql-snow .ql-editor blockquote {
border-left: 4px solid #ccc;
margin-bottom: 5px;
margin-top: 5px;
padding-left: 16px;
}
.ql-snow .ql-editor code,
.ql-snow .ql-editor pre {
background-color: #f0f0f0;
border-radius: 3px;
}
.ql-snow .ql-editor pre {
white-space: pre-wrap;
margin-bottom: 5px;
margin-top: 5px;
padding: 5px 10px;
}
.ql-snow .ql-editor code {
font-size: 85%;
padding-bottom: 2px;
padding-top: 2px;
}
.ql-snow .ql-editor code:before,
.ql-snow .ql-editor code:after {
content: "\A0";
letter-spacing: -2px;
}
.ql-snow .ql-editor pre.ql-syntax {
background-color: #23241f;
color: #f8f8f2;
overflow: visible;
}
.ql-snow .ql-editor img {
max-width: 100%;
}
.ql-snow .ql-picker {
color: #444;
display: inline-block;
float: left;
font-size: 14px;
font-weight: 500;
height: 24px;
position: relative;
vertical-align: middle;
}
.ql-snow .ql-picker-label {
cursor: pointer;
display: inline-block;
height: 100%;
padding-left: 8px;
padding-right: 2px;
position: relative;
width: 100%;
}
.ql-snow .ql-picker-label::before {
display: inline-block;
line-height: 22px;
}
.ql-snow .ql-picker-options {
background-color: #fff;
display: none;
min-width: 100%;
padding: 4px 8px;
position: absolute;
white-space: nowrap;
}
.ql-snow .ql-picker-options .ql-picker-item {
cursor: pointer;
display: block;
padding-bottom: 5px;
padding-top: 5px;
}
.ql-snow .ql-picker.ql-expanded .ql-picker-label {
color: #ccc;
z-index: 2;
}
.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-fill {
fill: #ccc;
}
.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-stroke {
stroke: #ccc;
}
.ql-snow .ql-picker.ql-expanded .ql-picker-options {
display: block;
margin-top: -1px;
top: 100%;
z-index: 1;
}
.ql-snow .ql-color-picker,
.ql-snow .ql-icon-picker {
width: 28px;
}
.ql-snow .ql-color-picker .ql-picker-label,
.ql-snow .ql-icon-picker .ql-picker-label {
padding: 2px 4px;
}
.ql-snow .ql-color-picker .ql-picker-label svg,
.ql-snow .ql-icon-picker .ql-picker-label svg {
right: 4px;
}
.ql-snow .ql-icon-picker .ql-picker-options {
padding: 4px 0px;
}
.ql-snow .ql-icon-picker .ql-picker-item {
height: 24px;
width: 24px;
padding: 2px 4px;
}
.ql-snow .ql-color-picker .ql-picker-options {
padding: 3px 5px;
width: 152px;
}
.ql-snow .ql-color-picker .ql-picker-item {
border: 1px solid transparent;
float: left;
height: 16px;
margin: 2px;
padding: 0px;
width: 16px;
}
.ql-snow .ql-color-picker .ql-picker-item.ql-primary-color {
margin-bottom: toolbarPadding;
}
.ql-snow .ql-picker:not(.ql-color-picker):not(.ql-icon-picker) svg {
position: absolute;
margin-top: -9px;
right: 0;
top: 50%;
width: 18px;
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-label]:not([data-label=''])::before,
.ql-snow .ql-picker.ql-font .ql-picker-label[data-label]:not([data-label=''])::before,
.ql-snow .ql-picker.ql-size .ql-picker-label[data-label]:not([data-label=''])::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-label]:not([data-label=''])::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-label]:not([data-label=''])::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-label]:not([data-label=''])::before {
content: attr(data-label);
}
.ql-snow .ql-picker.ql-header {
width: 98px;
}
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
content: 'Normal';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
content: 'Heading 1';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
content: 'Heading 2';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
content: 'Heading 3';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
content: 'Heading 4';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
content: 'Heading 5';
}
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
content: 'Heading 6';
}
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
font-size: 2em;
}
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
font-size: 1.5em;
}
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
font-size: 1.17em;
}
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
font-size: 1em;
}
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
font-size: 0.83em;
}
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
font-size: 0.67em;
}
.ql-snow .ql-picker.ql-font {
width: 108px;
}
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
content: 'Sans Serif';
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=serif]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]::before {
content: 'Serif';
}
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=monospace]::before,
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before {
content: 'Monospace';
}
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]::before {
font-family: Georgia, Times New Roman, serif;
}
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before {
font-family: Monaco, Courier New, monospace;
}
.ql-snow .ql-picker.ql-size {
width: 98px;
}
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
content: 'Normal';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=small]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]::before {
content: 'Small';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=large]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]::before {
content: 'Large';
}
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=huge]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]::before {
content: 'Huge';
}
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]::before {
font-size: 10px;
}
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]::before {
font-size: 18px;
}
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]::before {
font-size: 32px;
}
.ql-snow .ql-color-picker.ql-background .ql-picker-item {
background-color: #fff;
}
.ql-snow .ql-color-picker.ql-color .ql-picker-item {
background-color: #000;
}
.ql-toolbar.ql-snow {
border: 1px solid #ccc;
box-sizing: border-box;
font-family: 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;
padding: 8px;
}
.ql-toolbar.ql-snow .ql-formats {
margin-right: 15px;
}
.ql-toolbar.ql-snow .ql-picker-label {
border: 1px solid transparent;
}
.ql-toolbar.ql-snow .ql-picker-options {
border: 1px solid transparent;
box-shadow: rgba(0,0,0,0.2) 0 2px 8px;
}
.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-label {
border-color: #ccc;
}
.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-options {
border-color: #ccc;
}
.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item.ql-selected,
.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item:hover {
border-color: #000;
}
.ql-toolbar.ql-snow + .ql-container.ql-snow {
border-top: 0px;
}
.ql-snow .ql-tooltip {
background-color: #fff;
border: 1px solid #ccc;
box-shadow: 0px 0px 5px #ddd;
color: #444;
margin-top: 10px;
padding: 5px 12px;
white-space: nowrap;
}
.ql-snow .ql-tooltip::before {
content: "Visit URL:";
line-height: 26px;
margin-right: 8px;
}
.ql-snow .ql-tooltip input[type=text] {
display: none;
border: 1px solid #ccc;
font-size: 13px;
height: 26px;
margin: 0px;
padding: 3px 5px;
width: 170px;
}
.ql-snow .ql-tooltip a.ql-preview {
display: inline-block;
max-width: 200px;
overflow-x: hidden;
text-overflow: ellipsis;
vertical-align: top;
}
.ql-snow .ql-tooltip a.ql-action::after {
border-right: 1px solid #ccc;
content: 'Edit';
margin-left: 16px;
padding-right: 8px;
}
.ql-snow .ql-tooltip a.ql-remove::before {
content: 'Remove';
margin-left: 8px;
}
.ql-snow .ql-tooltip a {
line-height: 26px;
}
.ql-snow .ql-tooltip.ql-editing a.ql-preview,
.ql-snow .ql-tooltip.ql-editing a.ql-remove {
display: none;
}
.ql-snow .ql-tooltip.ql-editing input[type=text] {
display: inline-block;
}
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
border-right: 0px;
content: 'Save';
padding-right: 0px;
}
.ql-snow .ql-tooltip[data-mode=link]::before {
content: "Enter link:";
}
.ql-snow .ql-tooltip[data-mode=formula]::before {
content: "Enter formula:";
}
.ql-snow .ql-tooltip[data-mode=video]::before {
content: "Enter video:";
}
.ql-snow a {
color: #06c;
}
.ql-container.ql-snow {
border: 1px solid #ccc;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,85 @@
<!DOCTYPE html>
<html>
<head>
<title>Quill</title>
<meta charset="utf-8">
<link rel="stylesheet" href="quill.snow.css" />
<style>
.standalone-container {
margin: 0;
width: 100%;
}
#bubble-container {
height: 100%;
}
#bubble-container div.ql-editor {
margin-top:3em;
}
.hidden {
display: none;
}
</style>
</head>
<body>
<div class="standalone-container">
<div id="bubble-container"></div>
</div>
<form><input type="hidden" name="md" id="md" />
<input id="btnSubmit" type="button" value="Valider" class="hidden" />
</form>
<div id="result"></div>
<script type="text/javascript" src="quill.min.js"></script>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="showdown.js"></script>
<script type="text/javascript" src="to-markdown.js"></script>
<script type="text/javascript" src="md-helpers.js"></script>
<script type="text/javascript">
var toolbarOptions = [
['bold', 'italic', 'underline', 'strike'], // toggled buttons
['blockquote', 'code-block'],
[{ 'header': 1 }, { 'header': 2 }], // custom button values
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
[{ 'indent': '-1' }, { 'indent': '+1' }], // outdent/indent
['clean'] // remove formatting button
];
var quill = new Quill('#bubble-container', {
modules: {
toolbar: toolbarOptions
},
placeholder: 'Composez votre texte ...',
theme: 'snow'
});
function getMD() {
return markdownize($('#bubble-container div.ql-editor').html())
}
quill.on('text-change', function (delta, oldDelta, source)
{
if (source === "user") {
$('#md').val(getMD());
$('#btnSubmit').removeClass('hidden');
}
});
$( document ).ready(function() {
$('#btnSubmit').on('click', function () {
$.get("hybrid:validate?md=" + encodeURIComponent(getMD()),
function(data,stat,jqXHR) { $('#result').html("Okay") })
})
});
</script>
</body>
</html>

View File

@ -0,0 +1,71 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="quill.snow.css" />
<style>
.standalone-container {
margin: 0;
width: 100%;
height: 100%;
}
#bubble-container {
width:100%;
height: 100%;
}
#bubble-container div.ql-editor {
margin-top:0;
}
.hidden {
display: none;
}
</style>
</head>
<body>
<h1>Title</h1>
<div class="standalone-container">
<div id="bubble-container"><h1><strong>Hello Estimate!</strong></h1>
</div>
</div>
<script type="text/javascript" src="quill.min.js"></script>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="showdown.js"></script>
<script type="text/javascript" src="to-markdown.js"></script>
<script type="text/javascript" src="md-helpers.js"></script>
<script type="text/javascript">
var toolbarOptions = [
['bold', 'italic', 'underline', 'strike'], // toggled buttons
['blockquote', 'code-block'],
[{ 'header': 1 }, { 'header': 2 }], // custom button values
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
[{ 'indent': '-1' }, { 'indent': '+1' }], // outdent/indent
['clean'] // remove formatting button
];
var quill = new Quill('#bubble-container', {
modules: {
toolbar: toolbarOptions
},
placeholder: 'Composez votre texte ...',
theme: 'snow'
});
function getMD() {
return markdownize($('#bubble-container div.ql-editor').html())
}
quill.on('text-change', function (delta, oldDelta, source)
{
if (source === "user") {
$.get("file:validate?md=" + encodeURIComponent(getMD()));
}
});
</script>
</body>
</html>

View File

@ -0,0 +1,842 @@
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.toMarkdown = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
/*
* to-markdown - an HTML to Markdown converter
*
* Copyright 2011+, Dom Christie
* Licenced under the MIT licence
*
*/
'use strict'
var toMarkdown
var converters
var mdConverters = require('./lib/md-converters')
var gfmConverters = require('./lib/gfm-converters')
var HtmlParser = require('./lib/html-parser')
var collapse = require('collapse-whitespace')
/*
* Utilities
*/
var blocks = ['address', 'article', 'aside', 'audio', 'blockquote', 'body',
'canvas', 'center', 'dd', 'dir', 'div', 'dl', 'dt', 'fieldset', 'figcaption',
'figure', 'footer', 'form', 'frameset', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
'header', 'hgroup', 'hr', 'html', 'isindex', 'li', 'main', 'menu', 'nav',
'noframes', 'noscript', 'ol', 'output', 'p', 'pre', 'section', 'table',
'tbody', 'td', 'tfoot', 'th', 'thead', 'tr', 'ul'
]
function isBlock (node) {
return blocks.indexOf(node.nodeName.toLowerCase()) !== -1
}
var voids = [
'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input',
'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'
]
function isVoid (node) {
return voids.indexOf(node.nodeName.toLowerCase()) !== -1
}
function htmlToDom (string) {
var tree = new HtmlParser().parseFromString(string, 'text/html')
collapse(tree.documentElement, isBlock)
return tree
}
/*
* Flattens DOM tree into single array
*/
function bfsOrder (node) {
var inqueue = [node]
var outqueue = []
var elem
var children
var i
while (inqueue.length > 0) {
elem = inqueue.shift()
outqueue.push(elem)
children = elem.childNodes
for (i = 0; i < children.length; i++) {
if (children[i].nodeType === 1) inqueue.push(children[i])
}
}
outqueue.shift()
return outqueue
}
/*
* Contructs a Markdown string of replacement text for a given node
*/
function getContent (node) {
var text = ''
for (var i = 0; i < node.childNodes.length; i++) {
if (node.childNodes[i].nodeType === 1) {
text += node.childNodes[i]._replacement
} else if (node.childNodes[i].nodeType === 3) {
text += node.childNodes[i].data
} else continue
}
return text
}
/*
* Returns the HTML string of an element with its contents converted
*/
function outer (node, content) {
return node.cloneNode(false).outerHTML.replace('><', '>' + content + '<')
}
function canConvert (node, filter) {
if (typeof filter === 'string') {
return filter === node.nodeName.toLowerCase()
}
if (Array.isArray(filter)) {
return filter.indexOf(node.nodeName.toLowerCase()) !== -1
} else if (typeof filter === 'function') {
return filter.call(toMarkdown, node)
} else {
throw new TypeError('`filter` needs to be a string, array, or function')
}
}
function isFlankedByWhitespace (side, node) {
var sibling
var regExp
var isFlanked
if (side === 'left') {
sibling = node.previousSibling
regExp = / $/
} else {
sibling = node.nextSibling
regExp = /^ /
}
if (sibling) {
if (sibling.nodeType === 3) {
isFlanked = regExp.test(sibling.nodeValue)
} else if (sibling.nodeType === 1 && !isBlock(sibling)) {
isFlanked = regExp.test(sibling.textContent)
}
}
return isFlanked
}
function flankingWhitespace (node, content) {
var leading = ''
var trailing = ''
if (!isBlock(node)) {
var hasLeading = /^[ \r\n\t]/.test(content)
var hasTrailing = /[ \r\n\t]$/.test(content)
if (hasLeading && !isFlankedByWhitespace('left', node)) {
leading = ' '
}
if (hasTrailing && !isFlankedByWhitespace('right', node)) {
trailing = ' '
}
}
return { leading: leading, trailing: trailing }
}
/*
* Finds a Markdown converter, gets the replacement, and sets it on
* `_replacement`
*/
function process (node) {
var replacement
var content = getContent(node)
// Remove blank nodes
if (!isVoid(node) && !/A|TH|TD/.test(node.nodeName) && /^\s*$/i.test(content)) {
node._replacement = ''
return
}
for (var i = 0; i < converters.length; i++) {
var converter = converters[i]
if (canConvert(node, converter.filter)) {
if (typeof converter.replacement !== 'function') {
throw new TypeError(
'`replacement` needs to be a function that returns a string'
)
}
var whitespace = flankingWhitespace(node, content)
if (whitespace.leading || whitespace.trailing) {
content = content.trim()
}
replacement = whitespace.leading +
converter.replacement.call(toMarkdown, content, node) +
whitespace.trailing
break
}
}
node._replacement = replacement
}
toMarkdown = function (input, options) {
options = options || {}
if (typeof input !== 'string') {
throw new TypeError(input + ' is not a string')
}
if (input === '') {
return ''
}
// Escape potential ol triggers
input = input.replace(/(\d+)\. /g, '$1\\. ')
var clone = htmlToDom(input).body
var nodes = bfsOrder(clone)
var output
converters = mdConverters.slice(0)
if (options.gfm) {
converters = gfmConverters.concat(converters)
}
if (options.converters) {
converters = options.converters.concat(converters)
}
// Process through nodes in reverse (so deepest child elements are first).
for (var i = nodes.length - 1; i >= 0; i--) {
process(nodes[i])
}
output = getContent(clone)
return output.replace(/^[\t\r\n]+|[\t\r\n\s]+$/g, '')
.replace(/\n\s+\n/g, '\n\n')
.replace(/\n{3,}/g, '\n\n')
}
toMarkdown.isBlock = isBlock
toMarkdown.isVoid = isVoid
toMarkdown.outer = outer
module.exports = toMarkdown
},{"./lib/gfm-converters":2,"./lib/html-parser":3,"./lib/md-converters":4,"collapse-whitespace":7}],2:[function(require,module,exports){
'use strict'
function cell (content, node) {
var index = Array.prototype.indexOf.call(node.parentNode.childNodes, node)
var prefix = ' '
if (index === 0) prefix = '| '
return prefix + content + ' |'
}
var highlightRegEx = /highlight highlight-(\S+)/
module.exports = [
{
filter: 'br',
replacement: function () {
return '\n'
}
},
{
filter: ['del', 's', 'strike'],
replacement: function (content) {
return '~~' + content + '~~'
}
},
{
filter: function (node) {
return node.type === 'checkbox' && node.parentNode.nodeName === 'LI'
},
replacement: function (content, node) {
return (node.checked ? '[x]' : '[ ]') + ' '
}
},
{
filter: ['th', 'td'],
replacement: function (content, node) {
return cell(content, node)
}
},
{
filter: 'tr',
replacement: function (content, node) {
var borderCells = ''
var alignMap = { left: ':--', right: '--:', center: ':-:' }
if (node.parentNode.nodeName === 'THEAD') {
for (var i = 0; i < node.childNodes.length; i++) {
var align = node.childNodes[i].attributes.align
var border = '---'
if (align) border = alignMap[align.value] || border
borderCells += cell(border, node.childNodes[i])
}
}
return '\n' + content + (borderCells ? '\n' + borderCells : '')
}
},
{
filter: 'table',
replacement: function (content) {
return '\n\n' + content + '\n\n'
}
},
{
filter: ['thead', 'tbody', 'tfoot'],
replacement: function (content) {
return content
}
},
// Fenced code blocks
{
filter: function (node) {
return node.nodeName === 'PRE' &&
node.firstChild &&
node.firstChild.nodeName === 'CODE'
},
replacement: function (content, node) {
return '\n\n```\n' + node.firstChild.textContent + '\n```\n\n'
}
},
// Syntax-highlighted code blocks
{
filter: function (node) {
return node.nodeName === 'PRE' &&
node.parentNode.nodeName === 'DIV' &&
highlightRegEx.test(node.parentNode.className)
},
replacement: function (content, node) {
var language = node.parentNode.className.match(highlightRegEx)[1]
return '\n\n```' + language + '\n' + node.textContent + '\n```\n\n'
}
},
{
filter: function (node) {
return node.nodeName === 'DIV' &&
highlightRegEx.test(node.className)
},
replacement: function (content) {
return '\n\n' + content + '\n\n'
}
}
]
},{}],3:[function(require,module,exports){
/*
* Set up window for Node.js
*/
var _window = (typeof window !== 'undefined' ? window : this)
/*
* Parsing HTML strings
*/
function canParseHtmlNatively () {
var Parser = _window.DOMParser
var canParse = false
// Adapted from https://gist.github.com/1129031
// Firefox/Opera/IE throw errors on unsupported types
try {
// WebKit returns null on unsupported types
if (new Parser().parseFromString('', 'text/html')) {
canParse = true
}
} catch (e) {}
return canParse
}
function createHtmlParser () {
var Parser = function () {}
// For Node.js environments
if (typeof document === 'undefined') {
var jsdom = require('jsdom')
Parser.prototype.parseFromString = function (string) {
return jsdom.jsdom(string, {
features: {
FetchExternalResources: [],
ProcessExternalResources: false
}
})
}
} else {
if (!shouldUseActiveX()) {
Parser.prototype.parseFromString = function (string) {
var doc = document.implementation.createHTMLDocument('')
doc.open()
doc.write(string)
doc.close()
return doc
}
} else {
Parser.prototype.parseFromString = function (string) {
var doc = new window.ActiveXObject('htmlfile')
doc.designMode = 'on' // disable on-page scripts
doc.open()
doc.write(string)
doc.close()
return doc
}
}
}
return Parser
}
function shouldUseActiveX () {
var useActiveX = false
try {
document.implementation.createHTMLDocument('').open()
} catch (e) {
if (window.ActiveXObject) useActiveX = true
}
return useActiveX
}
module.exports = canParseHtmlNatively() ? _window.DOMParser : createHtmlParser()
},{"jsdom":6}],4:[function(require,module,exports){
'use strict'
module.exports = [
{
filter: 'p',
replacement: function (content) {
return '\n\n' + content + '\n\n'
}
},
{
filter: 'br',
replacement: function () {
return ' \n'
}
},
{
filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
replacement: function (content, node) {
var hLevel = node.nodeName.charAt(1)
var hPrefix = ''
for (var i = 0; i < hLevel; i++) {
hPrefix += '#'
}
return '\n\n' + hPrefix + ' ' + content + '\n\n'
}
},
{
filter: 'hr',
replacement: function () {
return '\n\n* * *\n\n'
}
},
{
filter: ['em', 'i'],
replacement: function (content) {
return '_' + content + '_'
}
},
{
filter: ['strong', 'b'],
replacement: function (content) {
return '**' + content + '**'
}
},
{
filter: ['u'],
replacement: function (content) {
return '_' + content + '_'
}
},
{
filter: ['del', 's', 'strike'],
replacement: function (content) {
return '~~' + content + '~~'
}
},
{
filter: 'div',
replacement: function (content) {
return content + '\n\n'
}
},
// Inline code
{
filter: function (node) {
var hasSiblings = node.previousSibling || node.nextSibling
var isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings
return node.nodeName === 'CODE' && !isCodeBlock
},
replacement: function (content) {
return '`' + content + '`'
}
},
{
filter: function (node) {
return node.nodeName === 'A' && node.getAttribute('href')
},
replacement: function (content, node) {
var titlePart = node.title ? ' "' + node.title + '"' : ''
return '[' + content + '](' + node.getAttribute('href') + titlePart + ')'
}
},
{
filter: 'video',
replacement: function (content, node) {
var alt = node.getAttribute('alt') || ''
var src
for (var i = 0; i < node.childNodes.length; i++) {
if (node.childNodes[i].localName === 'source') {
src = node.childNodes[i].getAttribute('src')
break
} }
var title = node.title || ''
var titlePart = title ? ' "' + title + '"' : ''
return src ? '![video:' + alt + ']' + '(' + src + titlePart + ')' : ''
}
},
{
filter: 'audio',
replacement: function (content, node) {
var alt = node.getAttribute('alt') || ''
var src = node.getAttribute('src') || ''
if (!src) {
for (var i = 0; i < node.childNodes.length; i++) {
if (node.childNodes[i].localName === 'source') {
src = node.childNodes[i].getAttribute('src')
break
} } }
var title = node.title || ''
var titlePart = title ? ' "' + title + '"' : ''
return src ? '![audio:' + alt + ']' + '(' + src + titlePart + ')' : ''
}
},
{
filter: 'img',
replacement: function (content, node) {
var alt = node.alt || ''
var src = node.getAttribute('src') || ''
var title = node.title || ''
var titlePart = title ? ' "' + title + '"' : ''
return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : ''
}
},
// Code blocks
{
filter: function (node) {
return node.nodeName === 'PRE' && node.firstChild.nodeName === 'CODE'
},
replacement: function (content, node) {
return '\n\n ' + node.firstChild.textContent.replace(/\n/g, '\n ') + '\n\n'
}
},
{
filter: 'blockquote',
replacement: function (content) {
content = content.trim()
content = content.replace(/\n{3,}/g, '\n\n')
content = content.replace(/^/gm, '> ')
return '\n\n' + content + '\n\n'
}
},
{
filter: 'li',
replacement: function (content, node) {
content = content.replace(/^\s+/, '').replace(/\n/gm, '\n ')
var prefix = '* '
var parent = node.parentNode
var index = Array.prototype.indexOf.call(parent.children, node) + 1
prefix = /ol/i.test(parent.nodeName) ? index + '. ' : '* '
return prefix + content
}
},
{
filter: ['ul', 'ol'],
replacement: function (content, node) {
var strings = []
for (var i = 0; i < node.childNodes.length; i++) {
strings.push(node.childNodes[i]._replacement)
}
if (/li/i.test(node.parentNode.nodeName)) {
return '\n' + strings.join('\n')
}
return '\n\n' + strings.join('\n') + '\n\n'
}
},
{
filter: function (node) {
return this.isBlock(node)
},
replacement: function (content, node) {
return '\n\n' + this.outer(node, content) + '\n\n'
}
},
// Anything else!
{
filter: function () {
return true
},
replacement: function (content, node) {
return this.outer(node, content)
}
}
]
},{}],5:[function(require,module,exports){
/**
* This file automatically generated from `build.js`.
* Do not manually edit.
*/
module.exports = [
"address",
"article",
"aside",
"audio",
"blockquote",
"canvas",
"dd",
"div",
"dl",
"fieldset",
"figcaption",
"figure",
"footer",
"form",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"header",
"hgroup",
"hr",
"main",
"nav",
"noscript",
"ol",
"output",
"p",
"pre",
"section",
"table",
"tfoot",
"ul",
"video"
];
},{}],6:[function(require,module,exports){
},{}],7:[function(require,module,exports){
'use strict';
var voidElements = require('void-elements');
Object.keys(voidElements).forEach(function (name) {
voidElements[name.toUpperCase()] = 1;
});
var blockElements = {};
require('block-elements').forEach(function (name) {
blockElements[name.toUpperCase()] = 1;
});
/**
* isBlockElem(node) determines if the given node is a block element.
*
* @param {Node} node
* @return {Boolean}
*/
function isBlockElem(node) {
return !!(node && blockElements[node.nodeName]);
}
/**
* isVoid(node) determines if the given node is a void element.
*
* @param {Node} node
* @return {Boolean}
*/
function isVoid(node) {
return !!(node && voidElements[node.nodeName]);
}
/**
* whitespace(elem [, isBlock]) removes extraneous whitespace from an
* the given element. The function isBlock may optionally be passed in
* to determine whether or not an element is a block element; if none
* is provided, defaults to using the list of block elements provided
* by the `block-elements` module.
*
* @param {Node} elem
* @param {Function} blockTest
*/
function collapseWhitespace(elem, isBlock) {
if (!elem.firstChild || elem.nodeName === 'PRE') return;
if (typeof isBlock !== 'function') {
isBlock = isBlockElem;
}
var prevText = null;
var prevVoid = false;
var prev = null;
var node = next(prev, elem);
while (node !== elem) {
if (node.nodeType === 3) {
// Node.TEXT_NODE
var text = node.data.replace(/[ \r\n\t]+/g, ' ');
if ((!prevText || / $/.test(prevText.data)) && !prevVoid && text[0] === ' ') {
text = text.substr(1);
}
// `text` might be empty at this point.
if (!text) {
node = remove(node);
continue;
}
node.data = text;
prevText = node;
} else if (node.nodeType === 1) {
// Node.ELEMENT_NODE
if (isBlock(node) || node.nodeName === 'BR') {
if (prevText) {
prevText.data = prevText.data.replace(/ $/, '');
}
prevText = null;
prevVoid = false;
} else if (isVoid(node)) {
// Avoid trimming space around non-block, non-BR void elements.
prevText = null;
prevVoid = true;
}
} else {
node = remove(node);
continue;
}
var nextNode = next(prev, node);
prev = node;
node = nextNode;
}
if (prevText) {
prevText.data = prevText.data.replace(/ $/, '');
if (!prevText.data) {
remove(prevText);
}
}
}
/**
* remove(node) removes the given node from the DOM and returns the
* next node in the sequence.
*
* @param {Node} node
* @return {Node} node
*/
function remove(node) {
var next = node.nextSibling || node.parentNode;
node.parentNode.removeChild(node);
return next;
}
/**
* next(prev, current) returns the next node in the sequence, given the
* current and previous nodes.
*
* @param {Node} prev
* @param {Node} current
* @return {Node}
*/
function next(prev, current) {
if (prev && prev.parentNode === current || current.nodeName === 'PRE') {
return current.nextSibling || current.parentNode;
}
return current.firstChild || current.nextSibling || current.parentNode;
}
module.exports = collapseWhitespace;
},{"block-elements":5,"void-elements":8}],8:[function(require,module,exports){
/**
* This file automatically generated from `pre-publish.js`.
* Do not manually edit.
*/
module.exports = {
"area": true,
"base": true,
"br": true,
"col": true,
"embed": true,
"hr": true,
"img": true,
"input": true,
"keygen": true,
"link": true,
"menuitem": true,
"meta": true,
"param": true,
"source": true,
"track": true,
"wbr": true
};
},{}]},{},[1])(1)
});

View File

@ -0,0 +1,356 @@
// ***********************************************************************
// Assembly : XLabs.Forms.Droid
// Author : XLabs Team
// Created : 12-27-2015
//
// Last Modified By : XLabs Team
// Last Modified On : 01-04-2016
// ***********************************************************************
// <copyright file="XFormsApp.cs" company="XLabs Team">
// Copyright (c) XLabs Team. All rights reserved.
// </copyright>
// <summary>
// This project is licensed under the Apache 2.0 license
// https://github.com/XLabs/Xamarin-Forms-Labs/blob/master/LICENSE
//
// XLabs is a open source project that aims to provide a powerfull and cross
// platform set of controls tailored to work with Xamarin Forms.
// </summary>
// ***********************************************************************
//
using System;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using XLabs.Platform.Device;
using XLabs.Platform.Mvvm;
using XLabs.Platform.Services;
using XLabs.Platform.Services.Email;
using XLabs.Platform.Services.Geolocation;
using XLabs.Platform.Services.IO;
using XLabs.Platform.Services.Media;
using Environment = Android.OS.Environment;
namespace XLabs.Forms
{
/// <summary>
/// Class XFormsApplicationDroid.
/// </summary>
public class XFormsCompatApplicationDroid :
global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
/// <summary>
/// Gets or sets the destroy.
/// </summary>
/// <value>The destroy.</value>
public EventHandler<EventArgs> Destroy { get; set; }
/// <summary>
/// Gets or sets the pause.
/// </summary>
/// <value>The pause.</value>
public EventHandler<EventArgs> Pause { get; set; }
/// <summary>
/// Gets or sets the restart.
/// </summary>
/// <value>The restart.</value>
public EventHandler<EventArgs> Restart { get; set; }
/// <summary>
/// Gets or sets the resume.
/// </summary>
/// <value>The resume.</value>
public EventHandler<EventArgs> Resume { get; set; }
/// <summary>
/// Gets or sets the start.
/// </summary>
/// <value>The start.</value>
public EventHandler<EventArgs> Start { get; set; }
/// <summary>
/// Gets or sets the stop.
/// </summary>
/// <value>The stop event handler.</value>
public EventHandler<EventArgs> Stop { get; set; }
/// <summary>
/// Called when [destroy].
/// </summary>
protected override void OnDestroy()
{
var handler = this.Destroy;
if (handler != null)
{
handler(this, new EventArgs());
}
base.OnDestroy();
}
/// <summary>
/// Called as part of the activity lifecycle when an activity is going into
/// the background, but has not (yet) been killed.
/// </summary>
/// <since version="Added in API level 1" />
/// <altmember cref="M:Android.App.Activity.OnResume" />
/// <altmember cref="M:Android.App.Activity.OnSaveInstanceState(Android.OS.Bundle)" />
/// <altmember cref="M:Android.App.Activity.OnStop" />
/// <remarks><para tool="javadoc-to-mdoc">Called as part of the activity lifecycle when an activity is going into
/// the background, but has not (yet) been killed. The counterpart to
/// <c><see cref="M:Android.App.Activity.OnResume" /></c>.
/// </para>
/// <para tool="javadoc-to-mdoc">When activity B is launched in front of activity A, this callback will
/// be invoked on A. B will not be created until A's <c><see cref="M:Android.App.Activity.OnPause" /></c> returns,
/// so be sure to not do anything lengthy here.
/// </para>
/// <para tool="javadoc-to-mdoc">This callback is mostly used for saving any persistent state the
/// activity is editing, to present a "edit in place" model to the user and
/// making sure nothing is lost if there are not enough resources to start
/// the new activity without first killing this one. This is also a good
/// place to do things like stop animations and other things that consume a
/// noticeable amount of CPU in order to make the switch to the next activity
/// as fast as possible, or to close resources that are exclusive access
/// such as the camera.
/// </para>
/// <para tool="javadoc-to-mdoc">In situations where the system needs more memory it may kill paused
/// processes to reclaim resources. Because of this, you should be sure
/// that all of your state is saved by the time you return from
/// this function. In general <c><see cref="M:Android.App.Activity.OnSaveInstanceState(Android.OS.Bundle)" /></c> is used to save
/// per-instance state in the activity and this method is used to store
/// global persistent data (in content providers, files, etc.)
/// </para>
/// <para tool="javadoc-to-mdoc">After receiving this call you will usually receive a following call
/// to <c><see cref="M:Android.App.Activity.OnStop" /></c> (after the next activity has been resumed and
/// displayed), however in some cases there will be a direct call back to
/// <c><see cref="M:Android.App.Activity.OnResume" /></c> without going through the stopped state.
/// </para>
/// <para tool="javadoc-to-mdoc">
/// <i>Derived classes must call through to the super class's
/// implementation of this method. If they do not, an exception will be
/// thrown.</i>
/// </para>
/// <para tool="javadoc-to-mdoc">
/// <format type="text/html">
/// <a href="http://developer.android.com/reference/android/app/Activity.html#onPause()" target="_blank">[Android Documentation]</a>
/// </format>
/// </para></remarks>
protected override void OnPause()
{
var handler = this.Pause;
if (handler != null)
{
handler(this, new EventArgs());
}
base.OnPause();
}
/// <summary>
/// Called after <c><see cref="M:Android.App.Activity.OnStop" /></c> when the current activity is being
/// re-displayed to the user (the user has navigated back to it).
/// </summary>
/// <since version="Added in API level 1" />
/// <altmember cref="M:Android.App.Activity.OnStop" />
/// <altmember cref="M:Android.App.Activity.OnStart" />
/// <altmember cref="M:Android.App.Activity.OnResume" />
/// <remarks><para tool="javadoc-to-mdoc">Called after <c><see cref="M:Android.App.Activity.OnStop" /></c> when the current activity is being
/// re-displayed to the user (the user has navigated back to it). It will
/// be followed by <c><see cref="M:Android.App.Activity.OnStart" /></c> and then <c><see cref="M:Android.App.Activity.OnResume" /></c>.
/// </para>
/// <para tool="javadoc-to-mdoc">For activities that are using raw <c><see cref="T:Android.Database.ICursor" /></c> objects (instead of
/// creating them through
/// <c><see cref="M:Android.App.Activity.ManagedQuery(Android.Net.Uri, System.String[], System.String[], System.String[], System.String[])" /></c>,
/// this is usually the place
/// where the cursor should be required (because you had deactivated it in
/// <c><see cref="M:Android.App.Activity.OnStop" /></c>.
/// </para>
/// <para tool="javadoc-to-mdoc">
/// <i>Derived classes must call through to the super class's
/// implementation of this method. If they do not, an exception will be
/// thrown.</i>
/// </para>
/// <para tool="javadoc-to-mdoc">
/// <format type="text/html">
/// <a href="http://developer.android.com/reference/android/app/Activity.html#onRestart()" target="_blank">[Android Documentation]</a>
/// </format>
/// </para></remarks>
protected override void OnRestart()
{
var handler = this.Restart;
if (handler != null)
{
handler(this, new EventArgs());
}
base.OnRestart();
}
/// <summary>
/// Called after <c><see cref="M:Android.App.Activity.OnRestoreInstanceState(Android.OS.Bundle)" /></c>, <c><see cref="M:Android.App.Activity.OnRestart" /></c>, or
/// <c><see cref="M:Android.App.Activity.OnPause" /></c>, for your activity to start interacting with the user.
/// </summary>
/// <since version="Added in API level 1" />
/// <altmember cref="M:Android.App.Activity.OnRestoreInstanceState(Android.OS.Bundle)" />
/// <altmember cref="M:Android.App.Activity.OnRestart" />
/// <altmember cref="M:Android.App.Activity.OnPostResume" />
/// <altmember cref="M:Android.App.Activity.OnPause" />
/// <remarks><para tool="javadoc-to-mdoc">Called after <c><see cref="M:Android.App.Activity.OnRestoreInstanceState(Android.OS.Bundle)" /></c>, <c><see cref="M:Android.App.Activity.OnRestart" /></c>, or
/// <c><see cref="M:Android.App.Activity.OnPause" /></c>, for your activity to start interacting with the user.
/// This is a good place to begin animations, open exclusive-access devices
/// (such as the camera), etc.
/// </para>
/// <para tool="javadoc-to-mdoc">Keep in mind that onResume is not the best indicator that your activity
/// is visible to the user; a system window such as the key guard may be in
/// front. Use <c><see cref="M:Android.App.Activity.OnWindowFocusChanged(System.Boolean)" /></c> to know for certain that your
/// activity is visible to the user (for example, to resume a game).
/// </para>
/// <para tool="javadoc-to-mdoc">
/// <i>Derived classes must call through to the super class's
/// implementation of this method. If they do not, an exception will be
/// thrown.</i>
/// </para>
/// <para tool="javadoc-to-mdoc">
/// <format type="text/html">
/// <a href="http://developer.android.com/reference/android/app/Activity.html#onResume()" target="_blank">[Android Documentation]</a>
/// </format>
/// </para></remarks>
protected override void OnResume()
{
var handler = this.Resume;
if (handler != null)
{
handler(this, new EventArgs());
}
base.OnResume();
}
/// <summary>
/// Called after <c><see cref="M:Android.App.Activity.OnCreate(Android.OS.Bundle)" /></c> or after <c><see cref="M:Android.App.Activity.OnRestart" /></c> when
/// the activity had been stopped, but is now again being displayed to the
/// user.
/// </summary>
/// <since version="Added in API level 1" />
/// <altmember cref="M:Android.App.Activity.OnCreate(Android.OS.Bundle)" />
/// <altmember cref="M:Android.App.Activity.OnStop" />
/// <altmember cref="M:Android.App.Activity.OnResume" />
/// <remarks><para tool="javadoc-to-mdoc">Called after <c><see cref="M:Android.App.Activity.OnCreate(Android.OS.Bundle)" /></c> or after <c><see cref="M:Android.App.Activity.OnRestart" /></c> when
/// the activity had been stopped, but is now again being displayed to the
/// user. It will be followed by <c><see cref="M:Android.App.Activity.OnResume" /></c>.
/// </para>
/// <para tool="javadoc-to-mdoc">
/// <i>Derived classes must call through to the super class's
/// implementation of this method. If they do not, an exception will be
/// thrown.</i>
/// </para>
/// <para tool="javadoc-to-mdoc">
/// <format type="text/html">
/// <a href="http://developer.android.com/reference/android/app/Activity.html#onStart()" target="_blank">[Android Documentation]</a>
/// </format>
/// </para></remarks>
protected override void OnStart()
{
var handler = this.Start;
if (handler != null)
{
handler(this, new EventArgs());
}
base.OnStart();
}
/// <summary>
/// Called when you are no longer visible to the user.
/// </summary>
/// <since version="Added in API level 1" />
/// <altmember cref="M:Android.App.Activity.OnRestart" />
/// <altmember cref="M:Android.App.Activity.OnResume" />
/// <altmember cref="M:Android.App.Activity.OnSaveInstanceState(Android.OS.Bundle)" />
/// <altmember cref="M:Android.App.Activity.OnDestroy" />
/// <remarks><para tool="javadoc-to-mdoc">Called when you are no longer visible to the user. You will next
/// receive either <c><see cref="M:Android.App.Activity.OnRestart" /></c>, <c><see cref="M:Android.App.Activity.OnDestroy" /></c>, or nothing,
/// depending on later user activity.
/// </para>
/// <para tool="javadoc-to-mdoc">Note that this method may never be called, in low memory situations
/// where the system does not have enough memory to keep your activity's
/// process running after its <c><see cref="M:Android.App.Activity.OnPause" /></c> method is called.
/// </para>
/// <para tool="javadoc-to-mdoc">
/// <i>Derived classes must call through to the super class's
/// implementation of this method. If they do not, an exception will be
/// thrown.</i>
/// </para>
/// <para tool="javadoc-to-mdoc">
/// <format type="text/html">
/// <a href="http://developer.android.com/reference/android/app/Activity.html#onStop()" target="_blank">[Android Documentation]</a>
/// </format>
/// </para></remarks>
protected override void OnStop()
{
var handler = this.Stop;
if (handler != null)
{
handler(this, new EventArgs());
}
base.OnStop();
}
}
/// <summary>
/// Class XFormsAppDroid.
/// </summary>
public class XFormsCompatAppDroid : XFormsApp<XFormsCompatApplicationDroid>
{
/// <summary>
/// Initializes a new instance of the <see cref="XFormsAppDroid"/> class.
/// </summary>
public XFormsCompatAppDroid() { }
/// <summary>
/// Initializes a new instance of the <see cref="XFormsAppDroid"/> class.
/// </summary>
/// <param name="app">The application.</param>
public XFormsCompatAppDroid(XFormsCompatApplicationDroid app) : base(app) { }
/// <summary>
/// Raises the back press.
/// </summary>
public void RaiseBackPress()
{
this.OnBackPress();
}
/// <summary>
/// Called when [initialize].
/// </summary>
/// <param name="app">The application.</param>
/// <param name="initServices">Should initialize services.</param>
protected override void OnInit(XFormsCompatApplicationDroid app, bool initServices = true)
{
this.AppContext.Start += (o, e) => this.OnStartup();
this.AppContext.Stop += (o, e) => this.OnClosing();
this.AppContext.Pause += (o, e) => this.OnSuspended();
this.AppContext.Resume += (o, e) => this.OnResumed();
this.AppDataDirectory = Environment.ExternalStorageDirectory.AbsolutePath;
this.Orientation = AppContext.RequestedOrientation == Android.Content.PM.ScreenOrientation.Portrait ?
Enums.Orientation.Portrait : Enums.Orientation.None;
if (initServices)
{
DependencyService.Register<TextToSpeechService>();
DependencyService.Register<Geolocator>();
DependencyService.Register<MediaPicker>();
DependencyService.Register<SoundService>();
DependencyService.Register<EmailService>();
DependencyService.Register<FileManager>();
DependencyService.Register<AndroidDevice>();
}
base.OnInit(app);
}
}
}

View File

@ -0,0 +1,9 @@
Devic Info Readme
Find the most up to date information at: https://github.com/jamesmontemagno/Xamarin.Plugins
**IMPORTANT**
Windows Phone:
Permissions to add:
ID_CAP_IDENTITY_DEVICE

View File

@ -0,0 +1,44 @@
// Helpers/Settings.cs This file was automatically added when you installed the Settings Plugin. If you are not using a PCL then comment this file back in to use it.
using Plugin.Settings;
using Plugin.Settings.Abstractions;
namespace BookAStar.Droid.Helpers
{
/// <summary>
/// This is the Settings static class that can be used in your Core solution or in any
/// of your client applications. All settings are laid out the same exact way with getters
/// and setters.
/// </summary>
public static class Settings
{
private static ISettings AppSettings
{
get
{
return CrossSettings.Current;
}
}
#region Setting Constants
private const string SettingsKey = "settings_key";
private static readonly string SettingsDefault = string.Empty;
#endregion
public static string GeneralSettings
{
get
{
return AppSettings.GetValueOrDefault<string>(SettingsKey, SettingsDefault);
}
set
{
AppSettings.AddOrUpdateValue<string>(SettingsKey, value);
}
}
}
}

View File

@ -0,0 +1,121 @@
//
// PostJson.cs
//
// Author:
// Paul Schneider <paulschneider@free.fr>
//
// Copyright (c) 2015 Paul Schneider
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System.Net;
using System.IO;
using System.Json;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System;
using System.Diagnostics;
using BookAStar;
namespace Yavsc.Helpers
{
/// <summary>
/// Simple json post method.
/// </summary>
public class SimpleJsonPostMethod : IDisposable
{
private HttpWebRequest request=null;
/// <summary>
/// Initializes a new instance of the Yavsc.Helpers.SimpleJsonPostMethod class.
/// </summary>
/// <param name="pathToMethod">Path to method.</param>
public SimpleJsonPostMethod (string pathToMethod, string authorizationHeader = null)
{
request = (HttpWebRequest) WebRequest.Create ($"{BasePath}/{pathToMethod}");
request.Method = "POST";
request.Accept = "application/json";
request.ContentType = "application/json";
request.SendChunked = true;
request.TransferEncoding = "UTF-8";
if (authorizationHeader!=null)
request.Headers.Add($"Authorization: {authorizationHeader}");
}
public static string BasePath { get; private set; } = Constants.YavscApiUrl;
public void Dispose()
{
request.Abort();
}
/// <summary>
/// Invoke the specified query.
/// </summary>
/// <param name="query">Query.</param>
public TAnswer Invoke<TAnswer>(object query)
{
using (Stream streamQuery = request.GetRequestStream()) {
using (StreamWriter writer = new StreamWriter(streamQuery)) {
writer.Write (JsonConvert.SerializeObject(query));
}}
TAnswer ans = default (TAnswer);
using (WebResponse response = request.GetResponse ()) {
using (Stream responseStream = response.GetResponseStream ()) {
using (StreamReader rdr = new StreamReader (responseStream)) {
ans = (TAnswer) JsonConvert.DeserializeObject<TAnswer> (rdr.ReadToEnd ());
}
}
response.Close();
}
return ans;
}
public async Task<JsonValue> InvokeJson(object query)
{
JsonValue jsonDoc = null;
try
{
using (Stream streamQuery = request.GetRequestStream())
{
using (StreamWriter writer = new StreamWriter(streamQuery))
{
writer.Write(JsonConvert.SerializeObject(query));
}
}
using (WebResponse response = request.GetResponse())
{
using (Stream stream = response.GetResponseStream())
{
if (stream.Length > 0)
jsonDoc = await Task.Run(() => JsonObject.Load(stream));
}
response.Close();
}
}
catch (WebException ex)
{
// TODO err logging
Debug.Print($"Web request failed: {request.ToString()}\n" + ex.ToString());
}
catch (Exception ex)
{
Debug.Print($"Web request failed: {request.ToString()}\n" + ex.ToString());
}
return jsonDoc;
}
}
}

View File

@ -0,0 +1,25 @@
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Collections.Specialized;
using System.Net;
using System.Runtime.Serialization.Json;
using System.Text;
using BookAStar.Model.Auth.Account;
namespace BookAStar.Droid
{
public static class YavscHelpers
{
public static void SetRegId(this User user, string regId)
{
if (user.YavscTokens == null)
throw new InvalidOperationException();
}
}
}

View File

@ -0,0 +1,12 @@

using System;
public static class Html
{
public static Action<System.IO.TextWriter> Write(object o)
{
return new Action<System.IO.TextWriter>(w => w.Write(o));
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace BookAStar.Droid.Interfaces
{
interface IGCMessageHandler
{
void Handle( string from, Bundle data);
}
}

View File

@ -0,0 +1,503 @@
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Gms.Common;
using Android.OS;
using Android.Speech.Tts;
using Android.Util;
using Android.Widget;
using Newtonsoft.Json.Linq;
using Plugin.DeviceInfo;
using SQLite.Net;
using SQLite.Net.Platform.XamarinAndroid;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Xamarin.Auth;
using XLabs;
using XLabs.Caching;
using XLabs.Caching.SQLite;
using XLabs.Enums;
using XLabs.Forms;
using XLabs.Forms.Services;
using XLabs.Ioc;
using XLabs.Platform.Device;
using XLabs.Platform.Mvvm;
using XLabs.Platform.Services;
using XLabs.Platform.Services.Email;
using XLabs.Platform.Services.Media;
using XLabs.Serialization;
using XLabs.Serialization.JsonNET;
using Yavsc.Helpers;
using Yavsc.Models.Identity;
namespace BookAStar.Droid
{
using Android.Runtime;
using Android.Support.V4.App;
using Android.Support.V4.Content;
using BookAStar.Interfaces;
using Data;
using Droid.OAuth;
using Helpers;
using Interfaces;
using Model.Auth.Account;
using static Android.Manifest;
[Activity(Name = "fr.pschneider.bas.MainActivity", Label = "BookAStar", Theme = "@style/MainTheme", Icon = "@drawable/icon", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity :
// global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity,
XFormsCompatApplicationDroid,
IPlatform, IComponentContext
{
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
// FIXME usefull?
SetPersistent(true);
// global::Xamarin.Forms.Forms.SetTitleBarVisibility(Xamarin.Forms.AndroidTitleBarVisibility.Never);
//var tb = FindViewById<Android.Support.V7.Widget.Toolbar>(ToolbarResource);
// FIXME tb is null
var stb = new Android.Support.V7.Widget.Toolbar(this);
SetSupportActionBar(stb);
var tb = new Toolbar(this);
SetActionBar(tb);
if (Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat)
{
Android.Webkit.WebView.SetWebContentsDebuggingEnabled(true);
}
IXFormsApp<XFormsCompatApplicationDroid> app = null;
if (!Resolver.IsSet)
{
var xfapp = new XFormsCompatAppDroid();
this.SetIoc(xfapp);
}
else
{
app = Resolver.Resolve<IXFormsApp>() as IXFormsApp<XFormsCompatApplicationDroid>;
if (app != null)
app.AppContext = this;
}
global::Xamarin.Forms.Forms.Init(this, bundle);
global::Xamarin.FormsMaps.Init(this, bundle);
Xamarin.Forms.Forms.ViewInitialized += (sender, e) =>
{
if (!string.IsNullOrWhiteSpace(e.View.StyleId))
{
e.NativeView.ContentDescription = e.View.StyleId;
}
};
var fapp = new BookAStar.App(this);
LoadApplication(fapp);
var componentName = StartService(new Intent(this, typeof(YavscChooserTargetService)));
// TabLayoutResource = Resource.Layout.Tabbar;
// ToolbarResource = Resource.Layout.Toolbar;
/*
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
global::Xamarin.FormsMaps.Init(this, bundle);
LoadApplication(new App(this));
/* var x = typeof(Themes.DarkThemeResources);
x = typeof(Themes.LightThemeResources);
x = typeof(Themes.Android.UnderlineEffect); */
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == Constants.AllowBeATarget) {
if (grantResults.Length > 0)
{
if (grantResults[0] == Android.Content.PM.Permission.Granted)
{
// yay!
}
else
{
// Should we show an explanation?
if (ActivityCompat.ShouldShowRequestPermissionRationale(this,
Permission.BindChooserTargetService))
{
//Show permission explanation dialog...
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
throw new NotImplementedException();
}
else
{
//Never ask again selected, or device policy prohibits the app from having that permission.
//So, disable that feature, or fall back to another situation...
}
}
}
}
}
private SimpleContainer SetIoc(XFormsCompatAppDroid app)
{
var resolverContainer = new SimpleContainer();
app.Init(this);
var documents = app.AppDataDirectory;
var pathToDatabase = Path.Combine(documents, "xforms.db");
resolverContainer.Register<IDevice>(t => AndroidDevice.CurrentDevice)
.Register<IDisplay>(t => t.Resolve<IDevice>().Display)
.Register<IFontManager>(t => new FontManager(t.Resolve<IDisplay>()))
.Register<IEmailService, EmailService>()
.Register<IMediaPicker, MediaPicker>()
.Register<ITextToSpeechService, XLabs.Platform.Services.TextToSpeechService>()
.Register<IDependencyContainer>(resolverContainer)
.Register<IXFormsApp>(app)
.Register<ISecureStorage>(t => new KeyVaultStorage(t.Resolve<IDevice>().Id.ToCharArray()))
.Register<IJsonSerializer, JsonSerializer>()
.Register<ICacheProvider>(
t => new SQLiteSimpleCache(new SQLitePlatformAndroid(),
new SQLiteConnectionString(pathToDatabase, true), t.Resolve<IJsonSerializer>()));
Resolver.SetResolver(resolverContainer.GetResolver());
return resolverContainer;
}
public bool EnablePushNotifications(bool enable)
{
if (enable)
return StartNotifications();
else
return StopNotifications();
}
private string gCMStatusMessage = null;
public string GCMStatusMessage
{
get
{
return gCMStatusMessage;
}
}
public App AppContext
{
get; set;
}
bool StartNotifications()
{
if (IsPlayServicesAvailable(out gCMStatusMessage))
{
var intent = new Intent(this, typeof(GcmRegistrationIntentService));
StartService(intent);
return true;
}
return false;
}
bool StopNotifications()
{
return StopService(new Intent(this, typeof(GcmRegistrationIntentService)));
}
public void RevokeAccount(string userName)
{
var accStore = AccountStore.Create(this);
var accounts = accStore.FindAccountsForService(Constants.ApplicationName);
accStore.Delete(
accounts.Where(a => a.Username == userName).FirstOrDefault()
, Constants.ApplicationName);
Toast.MakeText(this,
Resource.String.yavscIdentRemoved
, ToastLength.Short);
}
public void OpenWeb(string Uri)
{
var u = global::Android.Net.Uri.Parse(Uri);
Intent i = new Intent(Intent.ActionView, u);
StartActivity(i);
}
protected override void OnStart()
{
base.OnStart();
if (MainSettings.PushNotifications)
StartNotifications();
long queryId = Intent.GetLongExtra("BookQueryId", 0);
if (queryId > 0)
{
Task.Run(async () =>
{
var query = DataManager.Instance.BookQueries.LocalGet(queryId);
App.ShowBookQuery(query);
});
}
}
public bool IsPlayServicesAvailable(out string msgText)
{
int resultCode = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.Success)
{
if (GoogleApiAvailability.Instance.IsUserResolvableError(resultCode))
msgText = GoogleApiAvailability.Instance.GetErrorString(resultCode);
else
{
msgText = "Sorry, this device is not supported";
Finish();
}
return false;
}
else
{
msgText = "Google Play Services is available.";
return true;
}
}
public void UploadJson(string data)
{
try
{
string url = "http://lua.pschneider.fr/api/BackOffice/SetRegistrationId";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
//using GET - request.Headers.Add ("Authorization","Authorizaation value");
request.ContentType = "application/json";
HttpWebResponse myResp = (HttpWebResponse)request.GetResponse();
string responseText;
using (var response = request.GetResponse())
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
responseText = reader.ReadToEnd();
Log.Debug(Constants.ApplicationName, responseText);
}
}
}
catch (WebException exception)
{
string responseText;
using (var reader = new StreamReader(exception.Response.GetResponseStream()))
{
responseText = reader.ReadToEnd();
Log.Debug("BookAStar", responseText);
}
}
}
public async Task<IEnumerable<Account>> GetAndroidAccounts()
{
return await Task.Run(() =>
{
var manager = AccountStore.Create(this);
return manager.FindAccountsForService(Constants.ApplicationName);
});
}
public void AddAccount()
{
var auth = new YaOAuth2Authenticator(
clientId: "d9be5e97-c19d-42e4-b444-0e65863b19e1",
clientSecret: "blouh",
scope: "profile",
authorizeUrl: new Uri(Constants.AuthorizeUrl),
redirectUrl: new Uri(Constants.RedirectUrl),
accessTokenUrl: new Uri(Constants.AccessTokenUrl));
Intent loginIntent = auth.GetUI(this);
var accStore = AccountStore.Create(this);
auth.Completed += (sender, eventArgs) =>
{
if (eventArgs.IsAuthenticated)
{
int expires_in = int.Parse(eventArgs.Account.Properties["expires_in"]);
var tokens = new Tokens
{
AccessToken = eventArgs.Account.Properties["access_token"],
RefreshToken = eventArgs.Account.Properties["refresh_token"],
ExpiresIn = expires_in,
TokenType = eventArgs.Account.Properties["token_type"]
};
RunOnUiThread(
async () =>
{
using (var client = new HttpClient())
{
// get me
using (var request = new HttpRequestMessage(HttpMethod.Get, Constants.UserInfoUrl))
{
request.Headers.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tokens.AccessToken);
using (var response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
string userJson = await response.Content.ReadAsStringAsync();
JObject jactiveUser = JObject.Parse(userJson);
Account acc = eventArgs.Account;
var uid = jactiveUser["Id"].Value<string>();
var username = jactiveUser["UserName"].Value<string>();
var roles = jactiveUser["Roles"].Values<string>().ToList();
var emails = jactiveUser["EMails"].Values<string>().ToList();
var avatar = jactiveUser["Avatar"].Value<string>();
var address = jactiveUser["Avatar"].Value<string>();
var newuser = new User
{
UserName = username,
EMails = emails,
Roles = roles,
Id = uid,
YavscTokens = tokens,
Avatar = avatar,
Address = address
};
MainSettings.SaveUser(newuser);
accStore.Save(acc, Constants.ApplicationName);
}
}
}
});
}
};
auth.Error += Auth_Error;
StartActivity(loginIntent);
}
private void Auth_Error(object sender, AuthenticatorErrorEventArgs e)
{
// TODO handle
}
public class GCMDeclaration : IGCMDeclaration
{
public string DeviceId
{ get; set; }
public string GCMRegistrationId
{ get; set; }
public string Model
{ get; set; }
public string Platform
{ get; set; }
public string Version
{ get; set; }
}
public IGCMDeclaration GetDeviceInfo()
{
var devinfo = CrossDeviceInfo.Current;
return new GCMDeclaration
{
DeviceId = devinfo.Id,
GCMRegistrationId = MainSettings.GoogleRegId,
Model = devinfo.Model,
Platform = devinfo.Platform.ToString(),
Version = devinfo.Version
};
}
[Obsolete("Use RemoteEntity to manage entities from API")]
public TAnswer InvokeApi<TAnswer>(string method, object arg)
{
using (var m =
new SimpleJsonPostMethod(
method, "Bearer " +
MainSettings.CurrentUser.YavscTokens.AccessToken
))
{
return m.Invoke<TAnswer>(arg);
}
}
public object InvokeApi(string method, object arg)
{
using (var m =
new SimpleJsonPostMethod(
method, "Bearer " +
MainSettings.CurrentUser.YavscTokens.AccessToken
))
{
return m.InvokeJson(arg);
}
}
public T Resolve<T>()
{
return (T)Resolver.Resolve(typeof(T));
}
public object Resolve(Type t)
{
return Resolver.Resolve(t);
}
protected override void OnSaveInstanceState(Bundle outState)
{
// TODO Save instance
base.OnSaveInstanceState(outState);
}
public override void OnStateNotSaved()
{
base.OnStateNotSaved();
}
public override void OnRestoreInstanceState(Bundle savedInstanceState, PersistableBundle persistentState)
{
base.OnRestoreInstanceState(savedInstanceState, persistentState);
}
private void CheckSharing()
{
// .BIND_CHOOSER_TARGET_SERVICE
// Here, thisActivity is the current activity
if (ContextCompat.CheckSelfPermission(this,
Permission.BindChooserTargetService) != Android.Content.PM.Permission.Granted)
{
ActivityCompat.RequestPermissions(this,
new String[] { Permission.BindChooserTargetService },
Constants.AllowBeATarget);
// Constants.AllowReadContacts is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
}
}

View File

@ -0,0 +1,63 @@
using System;
using Android.App;
using Android.OS;
using Android.Runtime;
using Plugin.CurrentActivity;
namespace BookAStar.Droid
{
//You can specify additional application information in this attribute
[Application]
public class MainApplication : Application, Application.IActivityLifecycleCallbacks
{
public MainApplication(IntPtr handle, JniHandleOwnership transer)
:base(handle, transer)
{
}
public override void OnCreate()
{
base.OnCreate();
RegisterActivityLifecycleCallbacks(this);
//A great place to initialize Xamarin.Insights and Dependency Services!
}
public override void OnTerminate()
{
base.OnTerminate();
UnregisterActivityLifecycleCallbacks(this);
}
public void OnActivityCreated(Activity activity, Bundle savedInstanceState)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivityDestroyed(Activity activity)
{
}
public void OnActivityPaused(Activity activity)
{
}
public void OnActivityResumed(Activity activity)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivitySaveInstanceState(Activity activity, Bundle outState)
{
}
public void OnActivityStarted(Activity activity)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivityStopped(Activity activity)
{
}
}
}

View File

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Webkit;
using Java.Interop;
namespace BookAStar.Droid.Markdown
{
public class JsBridgeMarkdown : Java.Lang.Object
{
readonly WeakReference<MarkdownViewRenderer> hybridWebViewRenderer;
public JsBridgeMarkdown(MarkdownViewRenderer hybridRenderer)
{
hybridWebViewRenderer = new WeakReference<MarkdownViewRenderer>(hybridRenderer);
}
[JavascriptInterface]
[Export("contentEdited")]
public void ContentEdited(string data)
{
MarkdownViewRenderer hybridRenderer;
if (hybridWebViewRenderer != null && hybridWebViewRenderer.TryGetTarget(out hybridRenderer))
{
hybridRenderer.Element.Markdown = data;
}
}
[JavascriptInterface]
[Export("jsLoaded")]
public void JSLoaded()
{
}
}
}

View File

@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Support.V7.App;
using XLabs.Ioc;
using XLabs.Platform.Mvvm;
using XLabs.Forms;
using static Android.Views.View;
namespace BookAStar.Droid.Markdown
{
class MDContextMenu : AppCompatDialog
{
private ActionMode mActionMode = null;
public MDContextMenu(Context context) : base(context)
{
}
public override void OnActionModeStarted(ActionMode mode)
{
if (mActionMode == null)
{
mActionMode = mode;
var menu = mode.Menu;
// Remove the default menu items (select all, copy, paste, search)
menu.Clear();
// If you want to keep any of the defaults,
// remove the items you don't want individually:
// menu.removeItem(android.R.id.[id_of_item_to_remove])
// Inflate your own menu items
mode.MenuInflater.Inflate(Resource.Menu.md_menu, menu);
}
mActionMode = mode;
base.OnActionModeStarted(mode);
}
public override void OnActionModeFinished(ActionMode mode)
{
base.OnActionModeFinished(mode);
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
}
public void OnCreateContextMenu(IContextMenu menu, View v, IContextMenuContextMenuInfo menuInfo)
{
/* if (menuInfo!=null)
{
var info = menuInfo.ToString();
}
menu.Add(0, 0, 0, "test");
var subMenu = menu.AddSubMenu(
0, 1, 1, "...");
subMenu.Add(0, 3, 0, "nkjnkjn");
var app = Resolver.Resolve<IXFormsApp>() as IXFormsApp<XFormsCompatApplicationDroid>;
var mgr = ClipboardManager.FromContext(app.AppContext);
if (mgr.HasText)
menu.Add(0, 0, 0, "Coller!");*/
//base.OnCreateContextMenu(menu, v, menuInfo);
}
}
}

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Webkit;
namespace BookAStar.Droid.Markdown
{
class MDWebView : WebView
{
public MDWebView (Context context) : base (context)
{
}
public override ActionMode StartActionMode(ActionMode.ICallback callback)
{
return base.StartActionMode(callback);
}
}
}

View File

@ -0,0 +1,397 @@
#pragma warning disable 1591
//------------------------------------------------------------------------------
// <auto-generated>
// Ce code a été généré par un outil.
// Version du runtime :4.0.30319.42000
//
// Les modifications apportées à ce fichier peuvent provoquer un comportement incorrect et seront perdues si
// le code est régénéré.
// </auto-generated>
//------------------------------------------------------------------------------
namespace BookAStar.Droid.Markdown
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorTemplatePreprocessor", "4.2.1.62")]
public partial class MarkdownEditor : MarkdownEditorBase
{
#line hidden
#line 1 "MarkdownEditor.cshtml"
public MarkdownViewModel Model { get; set; }
#line default
#line hidden
public override void Execute()
{
WriteLiteral("<!DOCTYPE html>\r\n<html>\r\n<head>\r\n <meta");
WriteLiteral(" charset=\"utf-8\"");
WriteLiteral(">\r\n <style>\r\n .standalone-container {\r\n margin: 0;\r\n " +
" width: 100%;\r\n height: 100%;\r\n }\r\n </style>\r\n");
#line 13 "MarkdownEditor.cshtml"
#line default
#line hidden
#line 13 "MarkdownEditor.cshtml"
if (Model.Editable)
{
#line default
#line hidden
WriteLiteral(" <link");
WriteLiteral(" rel=\"stylesheet\"");
WriteLiteral(" href=\"quill.snow.css\"");
WriteLiteral(" />\r\n");
WriteLiteral(@" <style>
#bubble-container {
width: 100%;
height: 100%;
}
#bubble-container div.ql-editor {
padding-top:3em;
}
.hidden {
display: none;
}
</style>
");
#line 30 "MarkdownEditor.cshtml"
}
#line default
#line hidden
WriteLiteral("</head>\r\n<body>\r\n <div");
WriteLiteral(" class=\"standalone-container\"");
WriteLiteral(">\r\n <div");
WriteLiteral(" id=\"bubble-container\"");
WriteLiteral(">");
#line 34 "MarkdownEditor.cshtml"
Write(Html.Write(Model.GetHtml()));
#line default
#line hidden
WriteLiteral("</div>\r\n </div>\r\n <script");
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral(" src=\"jquery.js\"");
WriteLiteral("></script>\r\n");
#line 37 "MarkdownEditor.cshtml"
#line default
#line hidden
#line 37 "MarkdownEditor.cshtml"
if (Model.Editable)
{
#line default
#line hidden
WriteLiteral(" <script");
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral(" src=\"quill.min.js\"");
WriteLiteral("></script>\r\n");
WriteLiteral(" <script");
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral(" src=\"showdown.js\"");
WriteLiteral("></script>\r\n");
WriteLiteral(" <script");
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral(" src=\"to-markdown.js\"");
WriteLiteral("></script>\r\n");
WriteLiteral(" <script");
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral(" src=\"md-helpers.js\"");
WriteLiteral("></script>\r\n");
#line 43 "MarkdownEditor.cshtml"
#line default
#line hidden
WriteLiteral(" <script");
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral(">\r\n var toolbarOptions = [\r\n [\'bold\', \'italic\', \'underline\', \'str" +
"ike\'], // toggled buttons\r\n [\'blockquote\', \'code-block\'],\r\n [{ " +
"\'header\': 1 }, { \'header\': 2 }, { \'header\': 3 }], // custom button" +
" values\r\n [{ \'list\': \'ordered\' }, { \'list\': \'bullet\' }],\r\n [{ \'indent\'" +
": \'-1\' }, { \'indent\': \'+1\' }], // outdent/indent\r\n [\'link\', \'image" +
"\', \'video\'],\r\n [\'clean\'] // remove " +
"formatting button\r\n ];\r\n\r\n var showImageUI = function (val" +
"ue) {\r\n if (value) {\r\n var href = prompt(\'Ente" +
"r the URL\');\r\n this.quill.format(\'image\', href);\r\n " +
" } else {\r\n this.quill.format(\'image\', false);\r\n " +
" }\r\n };\r\n\r\n $(document).ready(function () {\r\n " +
" var quill = new Quill(\'#bubble-container\', {\r\n modul" +
"es: {\r\n toolbar: toolbarOptions\r\n },\r\n" +
" placeholder: \'Composez votre texte ...\',\r\n " +
" theme: \'snow\'\r\n });\r\n\r\n function getMD() {\r\n " +
" return markdownize($(\'#bubble-container div.ql-editor\').html())\r" +
"\n }\r\n quill.on(\'text-change\', function (delta, old" +
"Delta, source) {\r\n if (source === \"user\") {\r\n " +
" contentEdited(getMD());\r\n }\r\n });\r\n " +
" var toolbar = quill.getModule(\'toolbar\');\r\n toolbar." +
"addHandler(\'image\', showImageUI);\r\n jsLoaded();\r\n });\r" +
"\n </script>\r\n");
#line 86 "MarkdownEditor.cshtml"
}
else
{
#line default
#line hidden
WriteLiteral(" <script");
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral(">\r\n $(document).ready(function() {\r\n jsLoaded();\r\n });\r\n" +
" </script>\r\n");
#line 94 "MarkdownEditor.cshtml"
}
#line default
#line hidden
WriteLiteral("</body>\r\n</html>\r\n");
}
}
// NOTE: this is the default generated helper class. You may choose to extract it to a separate file
// in order to customize it or share it between multiple templates, and specify the template's base
// class via the @inherits directive.
public abstract class MarkdownEditorBase
{
// This field is OPTIONAL, but used by the default implementation of Generate, Write, WriteAttribute and WriteLiteral
//
System.IO.TextWriter __razor_writer;
// This method is OPTIONAL
//
/// <summary>Executes the template and returns the output as a string.</summary>
/// <returns>The template output.</returns>
public string GenerateString ()
{
using (var sw = new System.IO.StringWriter ()) {
Generate (sw);
return sw.ToString ();
}
}
// This method is OPTIONAL, you may choose to implement Write and WriteLiteral without use of __razor_writer
// and provide another means of invoking Execute.
//
/// <summary>Executes the template, writing to the provided text writer.</summary>
/// <param name="writer">The TextWriter to which to write the template output.</param>
public void Generate (System.IO.TextWriter writer)
{
__razor_writer = writer;
Execute ();
__razor_writer = null;
}
// This method is REQUIRED, but you may choose to implement it differently
//
/// <summary>Writes a literal value to the template output without HTML escaping it.</summary>
/// <param name="value">The literal value.</param>
protected void WriteLiteral (string value)
{
__razor_writer.Write (value);
}
// This method is REQUIRED if the template contains any Razor helpers, but you may choose to implement it differently
//
/// <summary>Writes a literal value to the TextWriter without HTML escaping it.</summary>
/// <param name="writer">The TextWriter to which to write the literal.</param>
/// <param name="value">The literal value.</param>
protected static void WriteLiteralTo (System.IO.TextWriter writer, string value)
{
writer.Write (value);
}
// This method is REQUIRED, but you may choose to implement it differently
//
/// <summary>Writes a value to the template output, HTML escaping it if necessary.</summary>
/// <param name="value">The value.</param>
/// <remarks>The value may be a Action<System.IO.TextWriter>, as returned by Razor helpers.</remarks>
protected void Write (object value)
{
WriteTo (__razor_writer, value);
}
// This method is REQUIRED if the template contains any Razor helpers, but you may choose to implement it differently
//
/// <summary>Writes an object value to the TextWriter, HTML escaping it if necessary.</summary>
/// <param name="writer">The TextWriter to which to write the value.</param>
/// <param name="value">The value.</param>
/// <remarks>The value may be a Action<System.IO.TextWriter>, as returned by Razor helpers.</remarks>
protected static void WriteTo (System.IO.TextWriter writer, object value)
{
if (value == null)
return;
var write = value as Action<System.IO.TextWriter>;
if (write != null) {
write (writer);
return;
}
//NOTE: a more sophisticated implementation would write safe and pre-escaped values directly to the
//instead of double-escaping. See System.Web.IHtmlString in ASP.NET 4.0 for an example of this.
writer.Write(System.Net.WebUtility.HtmlEncode (value.ToString ()));
}
// This method is REQUIRED, but you may choose to implement it differently
//
/// <summary>
/// Conditionally writes an attribute to the template output.
/// </summary>
/// <param name="name">The name of the attribute.</param>
/// <param name="prefix">The prefix of the attribute.</param>
/// <param name="suffix">The suffix of the attribute.</param>
/// <param name="values">Attribute values, each specifying a prefix, value and whether it's a literal.</param>
protected void WriteAttribute (string name, string prefix, string suffix, params Tuple<string,object,bool>[] values)
{
WriteAttributeTo (__razor_writer, name, prefix, suffix, values);
}
// This method is REQUIRED if the template contains any Razor helpers, but you may choose to implement it differently
//
/// <summary>
/// Conditionally writes an attribute to a TextWriter.
/// </summary>
/// <param name="writer">The TextWriter to which to write the attribute.</param>
/// <param name="name">The name of the attribute.</param>
/// <param name="prefix">The prefix of the attribute.</param>
/// <param name="suffix">The suffix of the attribute.</param>
/// <param name="values">Attribute values, each specifying a prefix, value and whether it's a literal.</param>
///<remarks>Used by Razor helpers to write attributes.</remarks>
protected static void WriteAttributeTo (System.IO.TextWriter writer, string name, string prefix, string suffix, params Tuple<string,object,bool>[] values)
{
// this is based on System.Web.WebPages.WebPageExecutingBase
// Copyright (c) Microsoft Open Technologies, Inc.
// Licensed under the Apache License, Version 2.0
if (values.Length == 0) {
// Explicitly empty attribute, so write the prefix and suffix
writer.Write (prefix);
writer.Write (suffix);
return;
}
bool first = true;
bool wroteSomething = false;
for (int i = 0; i < values.Length; i++) {
Tuple<string,object,bool> attrVal = values [i];
string attPrefix = attrVal.Item1;
object value = attrVal.Item2;
bool isLiteral = attrVal.Item3;
if (value == null) {
// Nothing to write
continue;
}
// The special cases here are that the value we're writing might already be a string, or that the
// value might be a bool. If the value is the bool 'true' we want to write the attribute name instead
// of the string 'true'. If the value is the bool 'false' we don't want to write anything.
//
// Otherwise the value is another object (perhaps an IHtmlString), and we'll ask it to format itself.
string stringValue;
bool? boolValue = value as bool?;
if (boolValue == true) {
stringValue = name;
} else if (boolValue == false) {
continue;
} else {
stringValue = value as string;
}
if (first) {
writer.Write (prefix);
first = false;
} else {
writer.Write (attPrefix);
}
if (isLiteral) {
writer.Write (stringValue ?? value);
} else {
WriteTo (writer, stringValue ?? value);
}
wroteSomething = true;
}
if (wroteSomething) {
writer.Write (suffix);
}
}
// This method is REQUIRED. The generated Razor subclass will override it with the generated code.
//
///<summary>Executes the template, writing output to the Write and WriteLiteral methods.</summary>.
///<remarks>Not intended to be called directly. Call the Generate method instead.</remarks>
public abstract void Execute ();
}
}
#pragma warning restore 1591

View File

@ -0,0 +1,96 @@
@model MarkdownViewModel
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.standalone-container {
margin: 0;
width: 100%;
height: 100%;
}
</style>
@if (Model.Editable)
{
<link rel="stylesheet" href="quill.snow.css" />
<style>
#bubble-container {
width: 100%;
height: 100%;
}
#bubble-container div.ql-editor {
padding-top:3em;
}
.hidden {
display: none;
}
</style>
}
</head>
<body>
<div class="standalone-container">
<div id="bubble-container">@Html.Write(Model.GetHtml())</div>
</div>
<script type="text/javascript" src="jquery.js"></script>
@if (Model.Editable)
{
<script type="text/javascript" src="quill.min.js"></script>
<script type="text/javascript" src="showdown.js"></script>
<script type="text/javascript" src="to-markdown.js"></script>
<script type="text/javascript" src="md-helpers.js"></script>
<script type="text/javascript">
var toolbarOptions = [
['bold', 'italic', 'underline', 'strike'], // toggled buttons
['blockquote', 'code-block'],
[{ 'header': 1 }, { 'header': 2 }, { 'header': 3 }], // custom button values
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
[{ 'indent': '-1' }, { 'indent': '+1' }], // outdent/indent
['link', 'image', 'video'],
['clean'] // remove formatting button
];
var showImageUI = function (value) {
if (value) {
var href = prompt('Enter the URL');
this.quill.format('image', href);
} else {
this.quill.format('image', false);
}
};
$(document).ready(function () {
var quill = new Quill('#bubble-container', {
modules: {
toolbar: toolbarOptions
},
placeholder: 'Composez votre texte ...',
theme: 'snow'
});
function getMD() {
return markdownize($('#bubble-container div.ql-editor').html())
}
quill.on('text-change', function (delta, oldDelta, source) {
if (source === "user") {
contentEdited(getMD());
}
});
var toolbar = quill.getModule('toolbar');
toolbar.addHandler('image', showImageUI);
jsLoaded();
});
</script>
}
else
{
<script type="text/javascript">
$(document).ready(function() {
jsLoaded();
});
</script>
}
</body>
</html>

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Graphics;
namespace BookAStar.Droid.Markdown
{
public class MarkdownViewModel
{
protected static MarkdownDeep.Markdown markdown = new MarkdownDeep.Markdown();
public string Content { get; set; }
public bool Editable { get; set; }
public string GetHtml()
{
return markdown.Transform(Content);
}
public override string ToString()
{
return Content;
}
}
}

View File

@ -0,0 +1,120 @@
using BookAStar.Views;
using Android.Webkit;
using Xamarin.Forms.Platform.Android;
using BookAStar.Droid;
using System;
using Java.Interop;
using System.ComponentModel;
using Android.Views;
[assembly: Xamarin.Forms.ExportRenderer(typeof(MarkdownView), typeof(MarkdownViewRenderer))]
namespace BookAStar.Droid
{
using Markdown;
using XLabs.Forms;
using XLabs.Ioc;
using XLabs.Platform.Mvvm;
using static View;
public class MarkdownViewRenderer : ViewRenderer<MarkdownView, WebView>
{
private WebView editorView;
private MarkdownEditor editorTemplate = new MarkdownEditor();
const string jsLoadedJavaScriptFunction = "function jsLoaded(){jsBridge.jsLoaded()}";
const string contentEditedJavaScriptFunction = "function contentEdited(data){jsBridge.contentEdited(data)}";
public WebView EditorView
{
get
{
return editorView;
}
}
/// <summary>
/// To be called once document finished loading
/// </summary>
/// <param name="xview"></param>
/// <param name="view"></param>
public static async void AdjustHeightRequest(MarkdownView xview, WebView view)
{
if (view == null || xview == null) return;
var vch = view.ContentHeight;
// var oldH = xview.Height;
var newH = vch > xview.MinimumHeightRequest ? vch : xview.MinimumHeightRequest;
xview.HeightRequest = newH;
}
protected override void OnElementChanged(ElementChangedEventArgs<MarkdownView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
SetNativeControl(CreateNativeControl());
InjectJS(jsLoadedJavaScriptFunction);
InjectJS(contentEditedJavaScriptFunction);
}
if (e.OldElement != null)
{
// Unsubscribe
}
if (e.NewElement != null)
{
// Subscribe
editorTemplate.Model = new Markdown.MarkdownViewModel
{
Content = e.NewElement.Markdown, Editable = e.NewElement.Editable
};
var html = editorTemplate.GenerateString();
EditorView.LoadDataWithBaseURL("file:///android_asset/",
html, "text/html", "utf-8", null);
EditorView.SetBackgroundColor(e.NewElement.BackgroundColor.ToAndroid());
}
}
void InjectJS(string script)
{
if (Control != null)
{
Control.LoadUrl(string.Format("javascript: {0}", script));
}
}
MDContextMenu contextMenu;
private WebView CreateNativeControl()
{
editorView = new WebView(Context);
EditorView.SetWebChromeClient(
new MarkdownWebChromeClient()
);
EditorView.Settings.BuiltInZoomControls = false;
EditorView.Settings.JavaScriptEnabled = true;
EditorView.Settings.LoadsImagesAutomatically = true;
EditorView.Settings.SetAppCacheEnabled(true);
EditorView.Settings.AllowContentAccess = true;
EditorView.Settings.AllowFileAccess = true;
EditorView.Settings.AllowFileAccessFromFileURLs = true;
EditorView.Settings.AllowUniversalAccessFromFileURLs = true;
EditorView.Settings.BlockNetworkImage = false;
EditorView.Settings.BlockNetworkLoads = false;
EditorView.Settings.DomStorageEnabled = true;
EditorView.AddJavascriptInterface(new JsBridgeMarkdown(this), "jsBridge");
EditorView.ViewTreeObserver.PreDraw += ViewTreeObserver_PreDraw;
//var app = Resolver.Resolve<IXFormsApp>() as IXFormsApp<XFormsCompatApplicationDroid>;
//contextMenu = new MDContextMenu(app.AppContext);
//EditorView.SetOnCreateContextMenuListener(contextMenu);
return EditorView;
}
private void EditorView_Touch(object sender, TouchEventArgs e)
{
}
private void ViewTreeObserver_PreDraw(object sender, ViewTreeObserver.PreDrawEventArgs e)
{
AdjustHeightRequest(Element, Control);
}
}
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Webkit;
namespace BookAStar.Droid.Markdown
{
class MarkdownWebChromeClient : WebChromeClient
{
/*public override void OnConsoleMessage(string message, int lineNumber, string sourceID)
{
base.OnConsoleMessage(message, lineNumber, sourceID);
}*/
}
}

View File

@ -0,0 +1,73 @@
@model string
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="quill.snow.css" />
<style>
.standalone-container {
margin: 0;
width: 100%;
height: 100%;
}
#bubble-container {
width:100%;
height: 100%;
}
#bubble-container div.ql-editor {
margin-top:3em;
}
.hidden {
display: none;
}
</style>
</head>
<body>
<div class="standalone-container">
<div id="bubble-container">@Html.Write(Model)</div>
</div>
<script type="text/javascript" src="quill.min.js"></script>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="showdown.js"></script>
<script type="text/javascript" src="to-markdown.js"></script>
<script type="text/javascript" src="md-helpers.js"></script>
<script type="text/javascript">
var toolbarOptions = [
['bold', 'italic', 'underline', 'strike'], // toggled buttons
['blockquote', 'code-block'],
[{ 'header': 1 }, { 'header': 2 }], // custom button values
[{ 'list': 'ordered' }, { 'list': 'bullet' }],
[{ 'indent': '-1' }, { 'indent': '+1' }], // outdent/indent
['link', 'image', 'video'],
['clean'] // remove formatting button
];
$(document).ready(function () {
var quill = new Quill('#bubble-container', {
modules: {
toolbar: toolbarOptions
},
placeholder: 'Composez votre texte ...',
theme: 'snow'
});
function getMD() {
return markdownize($('#bubble-container div.ql-editor').html())
}
quill.on('text-change', function (delta, oldDelta, source) {
if (source === "user") {
invokeCSharpAction(getMD());
}
});
// TODO implement a dedicated injection
invokeCSharpAction(getMD());
});
</script>
</body>
</html>

View File

@ -0,0 +1,621 @@
using System;
using System.Threading.Tasks;
using System.Linq;
using System.Collections.Generic;
using Xamarin.Utilities;
using System.Net;
using System.Text;
using Xamarin.Auth;
using BookAStar.Droid.OAuth.Xamarin.Utilities;
namespace BookAStar.Droid.OAuth {
public class YaOAuth2Authenticator : WebRedirectAuthenticator
{
string clientId;
string clientSecret;
string scope;
Uri authorizeUrl;
Uri accessTokenUrl;
Uri redirectUrl;
GetUsernameAsyncFunc getUsernameAsync;
string requestState;
bool reportedForgery = false;
/// <summary>
/// Gets the client identifier.
/// </summary>
/// <value>The client identifier.</value>
public string ClientId
{
get { return this.clientId; }
}
/// <summary>
/// Gets the client secret.
/// </summary>
/// <value>The client secret.</value>
public string ClientSecret
{
get { return this.clientSecret; }
}
/// <summary>
/// Gets the authorization scope.
/// </summary>
/// <value>The authorization scope.</value>
public string Scope
{
get { return this.scope; }
}
/// <summary>
/// Gets the authorize URL.
/// </summary>
/// <value>The authorize URL.</value>
public Uri AuthorizeUrl
{
get { return this.authorizeUrl; }
}
/// <summary>
/// Gets the access token URL.
/// </summary>
/// <value>The URL used to request access tokens after an authorization code was received.</value>
public Uri AccessTokenUrl
{
get { return this.accessTokenUrl; }
}
public new Uri RedirectUrl
{
get { return this.redirectUrl; }
}
/// <summary>
/// Initializes a new <see cref="Xamarin.Auth.OAuth2Authenticator"/>
/// that authenticates using implicit granting (token).
/// </summary>
/// <param name='clientId'>
/// Client identifier.
/// </param>
/// <param name='scope'>
/// Authorization scope.
/// </param>
/// <param name='authorizeUrl'>
/// Authorize URL.
/// </param>
/// <param name='redirectUrl'>
/// Redirect URL.
/// </param>
/// <param name='getUsernameAsync'>
/// Method used to fetch the username of an account
/// after it has been successfully authenticated.
/// </param>
public YaOAuth2Authenticator(string clientId, string scope, Uri authorizeUrl, Uri redirectUrl, GetUsernameAsyncFunc getUsernameAsync = null)
: this (redirectUrl)
{
if (string.IsNullOrEmpty(clientId))
{
throw new ArgumentException("clientId must be provided", "clientId");
}
this.clientId = clientId;
this.scope = scope ?? "";
if (authorizeUrl == null)
{
throw new ArgumentNullException("authorizeUrl");
}
this.authorizeUrl = authorizeUrl;
this.getUsernameAsync = getUsernameAsync;
this.accessTokenUrl = null;
}
/// <summary>
/// Initializes a new instance <see cref="Xamarin.Auth.OAuth2Authenticator"/>
/// that authenticates using authorization codes (code).
/// </summary>
/// <param name='clientId'>
/// Client identifier.
/// </param>
/// <param name='clientSecret'>
/// Client secret.
/// </param>
/// <param name='scope'>
/// Authorization scope.
/// </param>
/// <param name='authorizeUrl'>
/// Authorize URL.
/// </param>
/// <param name='redirectUrl'>
/// Redirect URL.
/// </param>
/// <param name='accessTokenUrl'>
/// URL used to request access tokens after an authorization code was received.
/// </param>
/// <param name='getUsernameAsync'>
/// Method used to fetch the username of an account
/// after it has been successfully authenticated.
/// </param>
public YaOAuth2Authenticator(string clientId, string clientSecret, string scope, Uri authorizeUrl, Uri redirectUrl, Uri accessTokenUrl, GetUsernameAsyncFunc getUsernameAsync = null)
: this (redirectUrl, clientSecret, accessTokenUrl)
{
if (string.IsNullOrEmpty(clientId))
{
throw new ArgumentException("clientId must be provided", "clientId");
}
this.clientId = clientId;
if (string.IsNullOrEmpty(clientSecret))
{
throw new ArgumentException("clientSecret must be provided", "clientSecret");
}
this.clientSecret = clientSecret;
this.scope = scope ?? "";
if (authorizeUrl == null)
{
throw new ArgumentNullException("authorizeUrl");
}
this.authorizeUrl = authorizeUrl;
if (accessTokenUrl == null)
{
throw new ArgumentNullException("accessTokenUrl");
}
this.accessTokenUrl = accessTokenUrl;
if (redirectUrl == null)
throw new Exception("redirectUrl is null");
this.redirectUrl = redirectUrl;
this.getUsernameAsync = getUsernameAsync;
}
YaOAuth2Authenticator(Uri redirectUrl, string clientSecret = null, Uri accessTokenUrl = null)
: base (redirectUrl, redirectUrl)
{
this.clientSecret = clientSecret;
this.accessTokenUrl = accessTokenUrl;
//
// Generate a unique state string to check for forgeries
//
var chars = new char[16];
var rand = new Random();
for (var i = 0; i < chars.Length; i++)
{
chars[i] = (char)rand.Next((int)'a', (int)'z' + 1);
}
this.requestState = new string(chars);
}
bool IsImplicit { get { return accessTokenUrl == null; } }
/// <summary>
/// Method that returns the initial URL to be displayed in the web browser.
/// </summary>
/// <returns>
/// A task that will return the initial URL.
/// </returns>
public override Task<Uri> GetInitialUrlAsync()
{
var url = new Uri(string.Format(
"{0}?client_id={1}&redirect_uri={2}&response_type={3}&scope={4}&state={5}",
authorizeUrl.AbsoluteUri,
Uri.EscapeDataString(clientId),
Uri.EscapeDataString(RedirectUrl.AbsoluteUri),
IsImplicit ? "token" : "code",
Uri.EscapeDataString(scope),
Uri.EscapeDataString(requestState)));
var tcs = new TaskCompletionSource<Uri>();
tcs.SetResult(url);
return tcs.Task;
}
/// <summary>
/// Raised when a new page has been loaded.
/// </summary>
/// <param name='url'>
/// URL of the page.
/// </param>
/// <param name='query'>
/// The parsed query of the URL.
/// </param>
/// <param name='fragment'>
/// The parsed fragment of the URL.
/// </param>
protected override void OnPageEncountered(Uri url, IDictionary<string, string> query, IDictionary<string, string> fragment)
{
if (url.AbsoluteUri.StartsWith(this.redirectUrl.AbsoluteUri))
{
// if (!this.redirectUrl.Equals(url)) {
// this is not our redirect page,
// but perhaps one one the third party identity providers
// One don't check for a state here.
//
/* if (fragment.ContainsKey("continue")) {
var cont = fragment["continue"];
// TODO continue browsing this address
var tcs = new TaskCompletionSource<Uri>();
tcs.SetResult(new Uri(cont));
tcs.Task.RunSynchronously();
}
return;*/
// }
var all = new Dictionary<string, string>(query);
foreach (var kv in fragment)
all[kv.Key] = kv.Value;
//
// Check for forgeries
//
if (all.ContainsKey("state"))
{
if (all["state"] != requestState && !reportedForgery)
{
reportedForgery = true;
OnError("Invalid state from server. Possible forgery!");
return;
}
}
}
//
// Continue processing
//
base.OnPageEncountered(url, query, fragment);
}
/// <summary>
/// Raised when a new page has been loaded.
/// </summary>
/// <param name='url'>
/// URL of the page.
/// </param>
/// <param name='query'>
/// The parsed query string of the URL.
/// </param>
/// <param name='fragment'>
/// The parsed fragment of the URL.
/// </param>
protected override void OnRedirectPageLoaded(Uri url, IDictionary<string, string> query, IDictionary<string, string> fragment)
{
//
// Look for the access_token
//
if (fragment.ContainsKey("access_token"))
{
//
// We found an access_token
//
OnRetrievedAccountProperties(fragment);
}
else if (!IsImplicit)
{
//
// Look for the code
//
if (query.ContainsKey("code"))
{
var code = query["code"];
RequestAccessTokenAsync(code).ContinueWith(task => {
if (task.IsFaulted)
{
OnError(task.Exception);
}
else
{
OnRetrievedAccountProperties(task.Result);
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
else
{
OnError("Expected code in response, but did not receive one.");
return;
}
}
else
{
OnError("Expected access_token in response, but did not receive one.");
return;
}
}
/// <summary>
/// Asynchronously requests an access token with an authorization <paramref name="code"/>.
/// </summary>
/// <returns>
/// A dictionary of data returned from the authorization request.
/// </returns>
/// <param name='code'>The authorization code.</param>
/// <remarks>Implements: http://tools.ietf.org/html/rfc6749#section-4.1</remarks>
Task<IDictionary<string, string>> RequestAccessTokenAsync(string code)
{
var queryValues = new Dictionary<string, string> {
{ "grant_type", "authorization_code" },
{ "code", code },
{ "redirect_uri", RedirectUrl.AbsoluteUri },
{ "client_id", clientId }
};
if (!string.IsNullOrEmpty(clientSecret))
{
queryValues["client_secret"] = clientSecret;
}
return RequestAccessTokenAsync(queryValues);
}
/// <summary>
/// Asynchronously makes a request to the access token URL with the given parameters.
/// </summary>
/// <param name="queryValues">The parameters to make the request with.</param>
/// <returns>The data provided in the response to the access token request.</returns>
protected Task<IDictionary<string, string>> RequestAccessTokenAsync(IDictionary<string, string> queryValues)
{
var query = queryValues.FormEncode();
var req = WebRequest.Create(accessTokenUrl);
(req as HttpWebRequest).Accept = "application/json";
req.Method = "POST";
var body = Encoding.UTF8.GetBytes(query);
req.ContentLength = body.Length;
req.ContentType = "application/x-www-form-urlencoded";
using (var s = req.GetRequestStream())
{
s.Write(body, 0, body.Length);
s.Close();
}
var auth = req.GetResponseAsync().ContinueWith(task =>
{
var text = task.Result.GetResponseText();
req.Abort();
// Parse the response
var data = text.Contains("{") ? WebEx.JsonDecode(text) : WebEx.FormDecode(text);
if (data.ContainsKey("error"))
{
throw new AuthException("Error authenticating: " + data["error"]);
}
else if (data.ContainsKey("access_token"))
{
return data;
}
else
{
throw new AuthException("Expected access_token in access token response, but did not receive one.");
}
});
return auth;
}
/// <summary>
/// Event handler that is fired when an access token has been retreived.
/// </summary>
/// <param name='accountProperties'>
/// The retrieved account properties
/// </param>
protected virtual void OnRetrievedAccountProperties(IDictionary<string, string> accountProperties)
{
//
// Now we just need a username for the account
//
if (getUsernameAsync != null)
{
getUsernameAsync(accountProperties).ContinueWith(task => {
if (task.IsFaulted)
{
OnError(task.Exception);
}
else
{
OnSucceeded(task.Result, accountProperties);
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
else
{
OnSucceeded("", accountProperties);
}
}
}
//
// Copyright 2012, Xamarin Inc.
//
// 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.
//
namespace Xamarin.Utilities
{
using System;
using System.Net;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Linq;
using System.Globalization;
using Newtonsoft.Json.Linq;
internal static class WebEx
{
public static string GetCookie(this CookieContainer containers, Uri domain, string name)
{
var c = containers
.GetCookies(domain)
.Cast<Cookie>()
.FirstOrDefault(x => x.Name == name);
return c != null ? c.Value : "";
}
public static Encoding GetEncodingFromContentType(string contentType)
{
//
// TODO: Parse the Content-Type
//
return Encoding.UTF8;
}
public static string GetResponseText(this WebResponse response)
{
var httpResponse = response as HttpWebResponse;
var encoding = Encoding.UTF8;
if (httpResponse != null)
{
encoding = GetEncodingFromContentType(response.ContentType);
}
using (var s = response.GetResponseStream())
{
using (var r = new StreamReader(s, encoding))
{
return r.ReadToEnd();
}
}
}
public static Task<WebResponse> GetResponseAsync(this WebRequest request)
{
return Task
.Factory
.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);
}
static char[] AmpersandChars = new char[] { '&' };
static char[] EqualsChars = new char[] { '=' };
public static IDictionary<string, string> FormDecode(string encodedString)
{
var inputs = new Dictionary<string, string>();
if (encodedString.StartsWith("?") || encodedString.StartsWith("#"))
{
encodedString = encodedString.Substring(1);
}
var parts = encodedString.Split(AmpersandChars);
foreach (var p in parts)
{
var kv = p.Split(EqualsChars);
var k = Uri.UnescapeDataString(kv[0]);
var v = kv.Length > 1 ? Uri.UnescapeDataString(kv[1]) : "";
inputs[k] = v;
}
return inputs;
}
public static Dictionary<string, string> JsonDecode(string encodedString)
{
var result = new Dictionary<string, string>();
var jtoken = JToken.Parse(encodedString);
foreach (JProperty st in jtoken)
{
result.Add(st.Name, st.Value.ToString()) ;
}
return result;
}
public static string HtmlEncode(string text)
{
if (string.IsNullOrEmpty(text))
{
return "";
}
var sb = new StringBuilder(text.Length);
int len = text.Length;
for (int i = 0; i < len; i++)
{
switch (text[i])
{
case '<':
sb.Append("&lt;");
break;
case '>':
sb.Append("&gt;");
break;
case '"':
sb.Append("&quot;");
break;
case '&':
sb.Append("&amp;");
break;
default:
if (text[i] > 159)
{
sb.Append("&#");
sb.Append(((int)text[i]).ToString(CultureInfo.InvariantCulture));
sb.Append(";");
}
else
{
sb.Append(text[i]);
}
break;
}
}
return sb.ToString();
}
public static string GetValueFromJson(string json, string key)
{
var p = json.IndexOf("\"" + key + "\"");
if (p < 0) return "";
var c = json.IndexOf(":", p);
if (c < 0) return "";
var q = json.IndexOf("\"", c);
if (q < 0) return "";
var b = q + 1;
var e = b;
for (; e < json.Length && json[e] != '\"'; e++)
{
}
var r = json.Substring(b, e - b);
return r;
}
}
}
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-sdk android:minSdkVersion="15" />
<application android:label="$safeprojectname$"></application>
</manifest>

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="fr.pschneider.bas" android:installLocation="auto">
<uses-sdk android:minSdkVersion="15" />
<application android:allowBackup="true" android:label="Booking Star" android:icon="@drawable/icon" android:theme="@style/MainTheme" android:configChanges="navigation|screenLayout|orientation|screenSize|smallestScreenSize">
<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="AIzaSyBLSEDhZixwpHDsWmO2pKwgGDJReoTuQ7A" />
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
<receiver android:name="com.google.android.gms.gcm.GcmReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="fr.pschneider.bas" />
</intent-filter>
</receiver>
<activity android:name="fr.pschneider.bas.MainActivity" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="fr.pschneider.bas.SendFilesActivity" android:label="@string/send_to_app_name">
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="*/*" />
</intent-filter>
<meta-data android:name="android.service.chooser.chooser_target_service" android:value="fr.pschneider.bas.YavscChooserTargetService" />
</activity>
<service android:name="fr.pschneider.bas.YavscChooserTargetService" android:label="@string/app_name" android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE">
<intent-filter>
<action android:name="android.service.chooser.ChooserTargetService" />
</intent-filter>
</service>
<service android:name="fr.pschneider.bas.AccountChooserService">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data android:name="android.accounts.AccountAuthenticator" android:resource="@xml/authenticator" />
</service>
</application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAVE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<permission android:name="fr.pschneider.bas.permission.MAPS_RECEIVE" android:protectionLevel="signature" />
<uses-permission android:name="fr.pschneider.bas.permission.MAPS_RECEIVE" />
<permission android:name="fr.pschneider.bas.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="fr.pschneider.bas.permission.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.intent.RECEIVE" />
<uses-permission android:name="com.google.android.c2dm.intent.REGISTRATION" />
<uses-permission android:name="com.google.android.c2dm.intent.RETRY" />
<uses-permission android:name="android.permission.ACCOUNT_MANAGER" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT" />
<uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" />
<uses-permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
<uses-permission android:name="android.permission.PERSISTENT_ACTIVITY" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_SOCIAL_STREAM" />
</manifest>

View File

@ -0,0 +1,34 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Android.App;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("BookAStar.Droid")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BookAStar.Droid")]
[assembly: AssemblyCopyright("Copyright © Paul Albert Schneider 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("fr")]
[assembly: ComVisible(false)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
// Add some common permissions, these can be removed if not needed
[assembly: UsesPermission(Android.Manifest.Permission.Internet)]
[assembly: UsesPermission(Android.Manifest.Permission.WriteExternalStorage)]

View File

@ -0,0 +1,296 @@
// ***********************************************************************
// Assembly : XLabs.Forms.Droid
// Author : XLabs Team
// Created : 12-27-2015
//
// Last Modified By : XLabs Team
// Last Modified On : 01-04-2016
// ***********************************************************************
// <copyright file="ImageButtonRenderer.cs" company="XLabs Team">
// Copyright (c) XLabs Team. All rights reserved.
// </copyright>
// <summary>
// This project is licensed under the Apache 2.0 license
// https://github.com/XLabs/Xamarin-Forms-Labs/blob/master/LICENSE
//
// XLabs is a open source project that aims to provide a powerfull and cross
// platform set of controls tailored to work with Xamarin Forms.
// </summary>
// ***********************************************************************
//
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.Views;
using XLabs.Enums;
using XLabs.Forms.Extensions;
using Color = Xamarin.Forms.Color;
using View = Android.Views.View;
using BookAStar.Rendering;
using BookAStar.Views;
using Xamarin.Forms.Platform.Android.AppCompat;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using System.IO;
using BookAStar.Helpers;
using System.Reflection;
using System.Threading;
[assembly: ExportRenderer(typeof(ImageButton), typeof(ImageButtonRenderer))]
namespace BookAStar.Rendering
{
/// <summary>
/// Draws a button on the Android platform with the image shown in the right
/// position with the right size.
/// </summary>
public partial class ImageButtonRenderer : Xamarin.Forms.Platform.Android.AppCompat.ButtonRenderer
{
private static float _density = float.MinValue;
/// <summary>
/// Sets up the button including the image.
/// </summary>
/// <param name="e">The event arguments.</param>
private ImageButton ImageButton
{
get { return (ImageButton)Element; }
}
protected override async void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
_density = Resources.DisplayMetrics.Density;
var targetButton = Control;
if (targetButton != null) targetButton.SetOnTouchListener(TouchListener.Instance.Value);
if (Element != null && Element.Font != Font.Default && targetButton != null) targetButton.Typeface = Element.Font.ToExtendedTypeface(Context);
if (Element != null && ImageButton.Source != null) await SetImageSourceAsync(targetButton, ImageButton).ConfigureAwait(false);
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected override void Dispose (bool disposing)
{
base.Dispose (disposing);
if (disposing && Control != null) {
Control.Dispose ();
}
}
int imageWitdh = 0;
int imageHeight = 0;
int imageWitdhRequest = 0;
int imageHeightRequest = 0;
// this is called before OnElementChanged ...
/*
public override SizeRequest GetDesiredSize(int widthConstraint, int heightConstraint)
{
switch (ImageButton.Orientation)
{
case ImageOrientation.ImageOnBottom:
case ImageOrientation.ImageOnTop:
return base.GetDesiredSize(widthConstraint, heightConstraint+ imageHeightRequest);
case ImageOrientation.ImageToRight:
case ImageOrientation.ImageToLeft:
return base.GetDesiredSize(widthConstraint + imageWitdhRequest, heightConstraint);
default:
return base.GetDesiredSize(widthConstraint, heightConstraint);
}
}*/
/// <summary>
/// Sets the image source.
/// </summary>
/// <param name="targetButton">The target button.</param>
/// <param name="model">The model.</param>
/// <returns>A <see cref="Task"/> for the awaited operation.</returns>
private async Task SetImageSourceAsync(Android.Widget.Button targetButton, ImageButton model)
{
if (targetButton == null || targetButton.Handle == IntPtr.Zero || model == null) return;
// const int Padding = 10;
var source = model.IsEnabled ? model.Source : model.DisabledSource ?? model.Source;
using (var bitmap = await GetBitmapAsync(source))
{
if (bitmap == null)
targetButton.SetCompoundDrawables(null, null, null, null);
else
{
var drawable = new BitmapDrawable(bitmap);
var tintColor = model.IsEnabled ? model.ImageTintColor : model.DisabledImageTintColor;
if (tintColor != Color.Transparent)
{
drawable.SetTint(tintColor.ToAndroid());
drawable.SetTintMode(PorterDuff.Mode.SrcIn);
}
imageWitdh = drawable.Bitmap.Width;
imageHeight = drawable.Bitmap.Height;
imageWitdhRequest = (int)model.ImageWidthRequest;
imageHeightRequest = (int)model.ImageHeightRequest;
if (imageHeightRequest <= 0) imageHeightRequest = imageHeight;
if (imageWitdhRequest <= 0) imageWitdhRequest = imageWitdh;
using (var scaledDrawable = GetScaleDrawable(drawable, imageWitdh, imageHeight))
{
Drawable left = null;
Drawable right = null;
Drawable top = null;
Drawable bottom = null;
int padding = 2; // model.Padding;
targetButton.CompoundDrawablePadding = RequestToPixels(padding);
targetButton.Gravity = GravityFlags.CenterHorizontal | GravityFlags.CenterVertical;
switch (model.Orientation)
{
case ImageOrientation.ImageToLeft:
left = scaledDrawable;
if (ImageButton.HeightRequest < imageHeightRequest)
ImageButton.HeightRequest = imageHeightRequest;
break;
case ImageOrientation.ImageToRight:
right = scaledDrawable;
if (ImageButton.HeightRequest < imageHeightRequest)
ImageButton.HeightRequest = imageHeightRequest;
break;
case ImageOrientation.ImageOnTop:
top = scaledDrawable;
if (ImageButton.WidthRequest < imageWitdhRequest)
ImageButton.WidthRequest = imageWitdhRequest;
break;
case ImageOrientation.ImageOnBottom:
bottom = scaledDrawable;
if (ImageButton.WidthRequest < imageWitdhRequest)
ImageButton.WidthRequest = imageWitdhRequest;
break;
case ImageOrientation.ImageCentered:
top = scaledDrawable;
if (ImageButton.HeightRequest < imageHeightRequest)
ImageButton.HeightRequest = imageHeightRequest;
if (ImageButton.WidthRequest < imageWitdhRequest)
ImageButton.WidthRequest = imageWitdhRequest;
break;
}
targetButton.SetCompoundDrawables(left, top, right, bottom);
// this.MeasureChildren(model.ImageWidthRequest, model.ImageHeightRequest);
}
}
}
}
/// <summary>
/// Gets a <see cref="Bitmap"/> for the supplied <see cref="ImageSource"/>.
/// </summary>
/// <param name="source">The <see cref="ImageSource"/> to get the image for.</param>
/// <returns>A loaded <see cref="Bitmap"/>.</returns>
private async Task<Bitmap> GetBitmapAsync(ImageSource imagesource)
{
var uriImageLoader = imagesource as UriImageSource;
if (uriImageLoader != null && uriImageLoader.Uri != null)
{
using (var client = UserHelpers.CreateJsonClient())
{
using (var response = await client.GetAsync(uriImageLoader.Uri))
{
var data = await response.Content.ReadAsByteArrayAsync();
return await BitmapFactory.DecodeByteArrayAsync(data, 0, data.Length);
}
}
}
var resImageLoader = imagesource as StreamImageSource;
if (resImageLoader != null && resImageLoader.Stream != null)
{
return await BitmapFactory.DecodeStreamAsync(await resImageLoader.Stream(CancellationToken.None));
}
return null;
}
/// <summary>
/// Called when the underlying model's properties are changed.
/// </summary>
/// <param name="sender">The Model used.</param>
/// <param name="e">The event arguments.</param>
protected override async void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == ImageButton.SourceProperty.PropertyName ||
e.PropertyName == ImageButton.DisabledSourceProperty.PropertyName ||
e.PropertyName == VisualElement.IsEnabledProperty.PropertyName ||
e.PropertyName == ImageButton.ImageTintColorProperty.PropertyName ||
e.PropertyName == ImageButton.DisabledImageTintColorProperty.PropertyName)
{
await SetImageSourceAsync(Control, ImageButton).ConfigureAwait(false);
}
base.OnElementPropertyChanged(sender, e);
}
/// <summary>
/// Returns a <see cref="Drawable"/> with the correct dimensions from an
/// Android resource id.
/// </summary>
/// <param name="drawable">An android <see cref="Drawable"/>.</param>
/// <param name="width">The width to scale to.</param>
/// <param name="height">The height to scale to.</param>
/// <returns>A scaled <see cref="Drawable"/>.</returns>
private Drawable GetScaleDrawable(Drawable drawable, int width, int height)
{
var returnValue = new ScaleDrawable(drawable, 0, 100, 100).Drawable;
returnValue.SetBounds(0, 0, RequestToPixels(width), RequestToPixels(height));
return returnValue;
}
/// <summary>
/// Returns a drawable dimension modified according to the current display DPI.
/// </summary>
/// <param name="sizeRequest">The requested size in relative units.</param>
/// <returns>Size in pixels.</returns>
public int RequestToPixels(int sizeRequest)
{
if (_density == float.MinValue)
{
if (Resources.Handle == IntPtr.Zero || Resources.DisplayMetrics.Handle == IntPtr.Zero)
_density = 1.0f;
else
_density = Resources.DisplayMetrics.Density;
}
return (int)(sizeRequest * _density);
}
}
//Hot fix for the layout positioning issue on Android as described in http://forums.xamarin.com/discussion/20608/fix-for-button-layout-bug-on-android
class TouchListener : Java.Lang.Object, View.IOnTouchListener
{
public static readonly Lazy<TouchListener> Instance = new Lazy<TouchListener>(() => new TouchListener());
/// <summary>
/// Make TouchListener a singleton.
/// </summary>
private TouchListener()
{ }
public bool OnTouch(View v, MotionEvent e)
{
var buttonRenderer = v.Tag as Xamarin.Forms.Platform.Android.AppCompat.ButtonRenderer;
if (buttonRenderer != null && e.Action == MotionEventActions.Down) buttonRenderer.Control.Text = buttonRenderer.Element.Text;
return false;
}
}
}

View File

@ -0,0 +1,50 @@
Images, layout descriptions, binary blobs and string dictionaries can be included
in your application as resource files. Various Android APIs are designed to
operate on the resource IDs instead of dealing with images, strings or binary blobs
directly.
For example, a sample Android app that contains a user interface layout (main.xml),
an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
would keep its resources in the "Resources" directory of the application:
Resources/
drawable-hdpi/
icon.png
drawable-ldpi/
icon.png
drawable-mdpi/
icon.png
layout/
main.xml
values/
strings.xml
In order to get the build system to recognize Android resources, set the build action to
"AndroidResource". The native Android APIs do not operate directly with filenames, but
instead operate on resource IDs. When you compile an Android application that uses resources,
the build system will package the resources for distribution and generate a class called
"Resource" that contains the tokens for each one of the resources included. For example,
for the above Resources layout, this is what the Resource class would expose:
public class Resource {
public class drawable {
public const int icon = 0x123;
}
public class layout {
public const int main = 0x456;
}
public class strings {
public const int first_string = 0xabc;
public const int second_string = 0xbcd;
}
}
You would then use R.drawable.icon to reference the drawable/icon.png file, or Resource.layout.main
to reference the layout/main.xml file, or Resource.strings.first_string to reference the first
string in the dictionary file values/strings.xml.

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" />

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.TabLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/sliding_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:tabIndicatorColor="@android:color/white"
app:tabGravity="fill"
app:tabMode="fixed" />

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
android:popupTheme="@style/ThemeOverlay.AppCompat.Dark"
tools:context=".MainActivity"
app:layout_scrollFlags="scroll|enterAlways"
/>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/copy"
android:title="@string/copy"/>
<group android:id="@+id/group">
<item android:id="@+id/past"
android:title="@string/past"
android:showAsAction="ifRoom|withText"/>
</group>
<item android:id="@+id/submenu_character"
android:title="@string/character" >
<menu>
<item android:id="@+id/bold"
android:title="@string/bold" />
<item android:id="@+id/italic"
android:title="@string/italic" />
<item android:id="@+id/underline"
android:title="@string/underline" />
</menu>
</item>
<item android:id="@+id/submenu_paragraph"
android:title="@string/paragraph" >
<menu>
<item android:id="@+id/header1"
android:onClick="onGroupItemClick"
android:title="@string/header1" />
<item android:id="@+id/header2"
android:onClick="onGroupItemClick"
android:title="@string/header2" />
</menu>
</item>
</menu>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<color name="design_textinput_error_color" >#FFFF0000</color>
<color name="primary" type="color">#FF2196F3</color>
<color name="primaryDark" type="color">#FF1976D2</color>
<color name="accent" type="color">#FFFFC107</color>
<color name="windowBackground" type="color">#fffafafa</color>
<integer-array name="androidcolors">
<item>@color/primary</item>
<item>@color/primaryDark</item>
<item>@color/accent</item>
<item>@color/windowBackground</item>
</integer-array>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<resources>
<dimen name="btnwidth">56dp</dimen>
<dimen name="design_fab_content_size">56dp</dimen>
<dimen name="design_navigation_padding_top_default">6dp</dimen>
<dimen name="design_tab_min_width">15dp</dimen>
<dimen name="dialog_fixed_height_major">150dp</dimen>
<dimen name="dialog_fixed_width_major">250dp</dimen>
<dimen name="dialog_fixed_width_minor">100dp</dimen>
</resources>

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Booking star</string>
<string name="send_to_app_name">Vers les étoiles</string>
<string name="yavscIdentRemoved">Identification supprimée</string>
<string name="yavscAccountTypeName">Booking star</string>
<string name="cancel">Annuler</string>
<string name="Settings">Paramètres</string>
<string name="Title">Title</string>
<string name="Description">Description</string>
<string name="Date">Date</string>
<string name="Location">Location</string>
<string name="Pricing">Pricing</string>
<string name="url">url</string>
<string name="url_hint">url_hint</string>
<string name="picture">picture</string>
<string name="google_app_id">325408689282</string>
<string name="pref_screen_title">Comptes Booking Star</string>
<string name="account_authenticator_label">Comptes Booking Star</string>
<string name="copy">Copier</string>
<string name="past">Coller</string>
<string name="character">Caractère</string>
<string name="bold">Gras</string>
<string name="italic">Italique</string>
<string name="underline">Sousligné</string>
<string name="paragraph">Paragraphe</string>
<string name="header1">Titre</string>
<string name="header2">Sous-titre</string>
<string name="accounts">Comptes</string>
<string name="bookingstar_accounts_pref_screen_summary">
Préférences des comptes Booking Star
</string>
</resources>

View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<style name="MainTheme" parent="MainTheme.Base">
<item name="android:windowBackground">@color/windowBackground</item>
<item name="android:windowNoTitle">true</item>
<item name="android:statusBarColor">@color/primaryDark</item>
<item name="android:colorPrimaryDark">@color/primaryDark</item>
<item name="android:windowFullscreen">true</item>
</style>
<!-- Base theme applied no matter what API -->
<style name="MainTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
<!--If you are using revision 22.1 please use just windowNoTitle. Without android:-->
<item name="windowNoTitle">true</item>
<!--We will be using the toolbar so no need to show ActionBar-->
<item name="windowActionBar">false</item>
<!-- Set theme colors from http://www.google.com/design/spec/style/color.html#color-color-palette -->
<!-- colorPrimary is used for the default action bar background -->
<item name="colorPrimary">#2196F3</item>
<!-- colorPrimaryDark is used for the status bar -->
<item name="colorPrimaryDark">#1976D2</item>
<!-- colorAccent is used as the default value for colorControlActivated
which is used to tint widgets -->
<item name="colorAccent">#FF4081</item>
<!-- You can also set colorControlNormal, colorControlActivated
colorControlHighlight and colorSwitchThumbNormal. -->
<item name="windowActionModeOverlay">true</item>
<item name="android:datePickerDialogTheme">@style/AppCompatDialogStyle</item>
<!--We will be using the toolbar so no need to show ActionBar-->
<!-- <item name="android:actionBarStyle">@style/MyActionBar</item> -->
</style>
<style name="AppCompatDialogStyle" parent="Theme.AppCompat.Light.Dialog">
<item name="colorAccent">#FF4081</item>
</style>
<!--
<style name="MyActionBar" parent="@android:style/Widget.Holo.Light.ActionBar.Solid.Inverse">
<item name="android:background">#A97946</item>
</style> -->
</resources>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<!--
Base application theme for API 21+. This theme replaces
MyTheme from resources/values/styles.xml on API 21+ devices.
-->
<style name="MyTheme" parent="MyTheme.Base">
<item name="android:windowContentTransitions">true</item>
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<item name="android:windowAllowReturnTransitionOverlap">true</item>
<item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
<item name="android:windowSharedElementExitTransition">@android:transition/move</item>
</style>
</resources>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8" ?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="@string/accounts" />
<PreferenceScreen
android:key="bookingstar_accounts_pref_screen"
android:title="@string/pref_screen_title"
android:summary="@string/bookingstar_accounts_pref_screen_summary">
<intent
android:action="bookingstar_accounts_pref_screen.ACTION"
android:targetPackage="bookingstar_accounts_pref_screen.package"
android:targetClass="bookingstar_accounts_pref_screen.class" />
</PreferenceScreen>
</PreferenceScreen>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
android:accountType="typeOfAuthenticator"
android:icon="@drawable/icon"
android:smallIcon="@drawable/icon"
android:label="@string/account_authenticator_label"
android:accountPreferences="@xml/account_preferences"
/>

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
namespace BookAStar.Droid
{
[Activity(Name= "fr.pschneider.bas.SendFilesActivity", Label = "SendFilesActivity")]
public class SendFilesActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your application here
}
}
}

View File

@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using BookAStar.Droid.OAuth;
namespace BookAStar.Droid.Services
{
[Service(
Name = "fr.pschneider.bas.AccountChooserService",
Label = "Yavsc accounts service",
Icon = "@drawable/icon",
Exported = true,
Enabled = true
)]
[IntentFilter(new String[] { "android.accounts.AccountAuthenticator" })]
class AccountChooserService : Service
{
public static YaOAuth2Authenticator authenticator;
public override void OnCreate()
{
base.OnCreate();
}
public override IBinder OnBind(Intent intent)
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using BookAStar.Droid.Interfaces;
using Newtonsoft.Json;
using BookAStar.Model.Social;
using BookAStar.Data;
using BookAStar.Model;
namespace BookAStar.Droid.Services.GCMHandlers
{
class BookQueryGCMHandler : GCMessageHandler
{
public BookQueryGCMHandler(Context context,
NotificationManager manager,
Notification.Builder builder) : base(context,manager,builder)
{
}
/// <summary>
/// Prend en charge le message push
/// contenant une nouvelle demande de rendez-vous
/// </summary>
/// <param name="from"></param>
/// <param name="data"></param>
public override void Handle(string from, Bundle data)
{
var locationJson = data.GetString("Location");
var location = JsonConvert.DeserializeObject<Location>(locationJson);
var cid = long.Parse(data.GetString("Id"));
var clientJson = data.GetString("Client");
var client = JsonConvert.DeserializeObject<ClientProviderInfo>(clientJson);
var bq = new BookQuery
{
Id = cid,
Location = location,
Client = client,
Reason = data.GetString("Reason")
};
var dateString = data.GetString("EventDate");
DateTime evDate;
if (DateTime.TryParse(dateString, out evDate))
{
bq.EventDate = evDate;
}
SendBookQueryNotification(bq);
}
/// <summary>
/// Notifie la demande
/// </summary>
/// <param name="bquery"></param>
void SendBookQueryNotification(BookQuery bquery)
{
DataManager.Instance.BookQueries.Merge(bquery);
var bookquerynotifications = DataManager.Instance.BookQueries.Where(
q => !q.Read && q.EventDate > DateTime.Now
).ToArray();
var count = bookquerynotifications.Length;
var multiple = count > 1;
var title =
multiple ? $"{count} demandes" : bquery.Client.UserName;
var message = $"{bquery.EventDate} {bquery.Client.UserName} {bquery.Location.Address}\n {bquery.Reason}";
var intent = new Intent(context, typeof(MainActivity));
intent.AddFlags(ActivityFlags.ClearTop);
intent.PutExtra("BookQueryId", bquery.Id);
var pendingIntent = PendingIntent.GetActivity(context, 0, intent, PendingIntentFlags.OneShot);
Notification.InboxStyle inboxStyle = new Notification.InboxStyle();
int maxil = 5;
for (int cn = 0; cn < count && cn < maxil; cn++)
{
inboxStyle.AddLine(bookquerynotifications[cn].Client.UserName);
}
if (count > maxil)
inboxStyle.SetSummaryText($"Plus {count - maxil} autres");
else inboxStyle.SetSummaryText((string)null);
notificationBuilder.SetContentTitle(title).SetContentText(message)
.SetStyle(inboxStyle)
.SetContentIntent(pendingIntent);
var notification = notificationBuilder.Build();
notificationManager.Notify(bookQueryNotificationId, notification);
}
int bookQueryNotificationId = 1;
}
}

View File

@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Newtonsoft.Json;
using BookAStar.Model.Social;
using BookAStar.Model;
using BookAStar.Model.Workflow;
using BookAStar.Data;
namespace BookAStar.Droid.Services.GCMHandlers
{
class EstimateGCMHandler: GCMessageHandler
{
public EstimateGCMHandler(Context context,
NotificationManager manager,
Notification.Builder builder) :
base(context,manager,builder)
{
}
public override void Handle(string from, Bundle data)
{
var locationJson = data.GetString("Location");
var location = JsonConvert.DeserializeObject<Location>(locationJson);
var eid = long.Parse(data.GetString("Id"));
var clientJson = data.GetString("Client");
var client = JsonConvert.DeserializeObject<ClientProviderInfo>(clientJson);
var estimate = new Estimate
{
Id = eid
};
var dateString = data.GetString("ProviderValidationDate");
DateTime evDate;
if (DateTime.TryParse(dateString, out evDate))
{
estimate.ProviderValidationDate = evDate;
}
Notify(estimate);
}
void Notify (Estimate estimate)
{
// do merge the data, even when no user is active
DataManager.Instance.Estimates.Merge(estimate);
if (MainSettings.CurrentUser == null) return;
var estimatenotifications = DataManager.Instance.Estimates.Where(
e => e.ClientApprouvalDate == default(DateTime) &&
e.ClientId == MainSettings.CurrentUser.Id
).OrderByDescending(e=>e.ProviderValidationDate).ToArray();
var count = estimatenotifications.Length;
var multiple = count > 1;
string title;
string message;
if (multiple)
{
StringBuilder tb = new StringBuilder();
int nc = 0;
foreach (var pro in estimatenotifications.Select(
e=>e.Owner
).Distinct())
{
nc++;
tb.Append($"{pro.UserName}");
if (nc > 3)
{
tb.Append(" et {count-nc} autres");
break;
}
else tb.Append(", ");
}
tb.Append("attendent votre validation de leur devis");
title = tb.ToString();
message =
string.Join("\n",
estimatenotifications.Select(
n => $"{n.Title} [{n.Owner.UserName}]\n").ToArray());
}
else
{
title = $"{estimate.Owner.UserName} attend votre validation de son devis";
message = $"{estimate.Title} ({estimate.Total} euro)\n({estimate.Query.Reason})";
}
var intent = new Intent(context, typeof(MainActivity));
intent.AddFlags(ActivityFlags.ClearTop);
intent.PutExtra("EstimateId", estimate.Id);
var pendingIntent = PendingIntent.GetActivity(context, 0, intent, PendingIntentFlags.OneShot);
Notification.InboxStyle inboxStyle = new Notification.InboxStyle();
int maxil = 5;
for (int cn = 0; cn < count && cn < maxil; cn++)
{
inboxStyle.AddLine(estimatenotifications[cn].Owner.UserName);
}
if (count > maxil)
inboxStyle.SetSummaryText($"Plus {count - maxil} autres");
else inboxStyle.SetSummaryText((string)null);
notificationBuilder.SetContentTitle(title).SetContentText(message)
.SetStyle(inboxStyle)
.SetContentIntent(pendingIntent);
var notification = notificationBuilder.Build();
notificationManager.Notify(notificationId, notification);
}
int notificationId = 2;
}
}

View File

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using BookAStar.Droid.Interfaces;
namespace BookAStar.Droid.Services.GCMHandlers
{
abstract class GCMessageHandler : IGCMessageHandler
{
protected Context context;
protected NotificationManager notificationManager;
protected Notification.Builder notificationBuilder;
public GCMessageHandler(Context context,
NotificationManager notificationManager,
Notification.Builder notificationBuilder)
{
this.context = context;
this.notificationBuilder = notificationBuilder;
this.notificationManager = notificationManager;
}
public abstract void Handle(string from, Bundle data);
}
}

View File

@ -0,0 +1,82 @@
using Android.App;
using Android.Content;
using Android.OS;
using Android.Gms.Gcm;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
namespace BookAStar.Droid.Services
{
using Model.Social;
using Model;
using Data;
using Interfaces;
using GCMHandlers;
namespace ClientApp
{
[Service(Exported = false), IntentFilter(new[] { "com.google.android.c2dm.intent.RECEIVE" })]
public class MyGcmListenerService : GcmListenerService
{
private Notification.Builder notificationBuilder;
NotificationManager notificationManager;
Dictionary<string, IGCMessageHandler> Handlers;
public override void OnCreate()
{
base.OnCreate();
notificationBuilder = new Notification.Builder(this)
.SetSmallIcon(Resource.Drawable.icon)
.SetAutoCancel(true);
notificationManager = (NotificationManager)GetSystemService(Context.NotificationService);
Handlers = new Dictionary<string, IGCMessageHandler>
{
{"BookQuery", new BookQueryGCMHandler(this,notificationManager,notificationBuilder) }
};
}
public override void OnDestroy()
{
base.OnDestroy();
notificationManager.Dispose();
notificationManager = null;
notificationBuilder.Dispose();
notificationBuilder = null;
}
public override void OnMessageReceived(string from, Bundle data)
{
var topic = data.GetString("Topic");
if (Handlers.ContainsKey(topic))
{
Handlers[topic].Handle(from, data);
}
else
{
throw new NotImplementedException(topic);
}
}
/* TODO cleaning
void SendNotification(string title, string message)
{
var intent = new Intent(this, typeof(MainActivity));
intent.AddFlags(ActivityFlags.ClearTop);
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.OneShot);
var notificationBuilder = new Notification.Builder(this)
.SetSmallIcon(Resource.Drawable.icon)
.SetContentTitle(title)
.SetContentText(message)
.SetAutoCancel(true)
.SetContentIntent(pendingIntent);
notificationManager.Notify(0, notificationBuilder.Build());
}*/
}
}
}

View File

@ -0,0 +1,112 @@
using System;
using Android.App;
using Android.Content;
using Android.Util;
using System.Net;
using System.IO;
using Android.Gms.Gcm;
using Android.Gms.Gcm.Iid;
using Android.OS;
using Android;
namespace BookAStar.Droid
{
[Service(Exported = false)]
class GcmRegistrationIntentService : IntentService
{
static object locker = new object();
public GcmRegistrationIntentService() : base("RegistrationIntentService") {
}
static PowerManager.WakeLock sWakeLock;
static object LOCK = new object();
public override void OnCreate()
{
base.OnCreate();
sWakeLock = PowerManager.FromContext(this).NewWakeLock(WakeLockFlags.Partial,
"BookAStar");
sWakeLock.Acquire();
}
public override void OnDestroy()
{
base.OnDestroy();
sWakeLock.Release();
}
protected override void OnHandleIntent (Intent intent)
{
try
{
Log.Info ("RegistrationIntentService", "Calling InstanceID.GetToken");
lock (locker)
{
var instanceID = InstanceID.GetInstance(this);
#if DEBUG
// When debugging, and application data/cache is preserved,
// a previous instance comes from another application installation
// and the old registration against GCM fails,
// until one delete it.
try
{
instanceID.DeleteInstanceID();
}
catch(Exception ex)
{
Debug.WaitForDebugger();
Log.Debug("bas.GCM", ex.StackTrace.ToString());
}
#endif
var senderid = MainSettings.GoogleSenderId;
var token = instanceID.GetToken ( senderid,
GoogleCloudMessaging.InstanceIdScope, null);
Log.Info ("RegistrationIntentService", "GCM Registration Token: " + token);
SendRegistrationToAppServer (token);
Subscribe (token);
}
}
catch (WebException e) {
Log.Debug ("RegistrationIntentService", "Failed to get a registration token");
if (e.Response!=null)
using (var s = e.Response.GetResponseStream ()) {
using (var r = new StreamReader (s)) {
var t = r.ReadToEnd ();
Log.Debug("RegistrationIntentService",t);
}
}
return;
}
catch (Exception e)
{
Log.Error ("RegistrationIntentService", "Failed to get a registration token");
Log.Error ("RegistrationIntentService", e.Message);
return;
}
}
void SendRegistrationToAppServer (string token)
{
MainSettings.GoogleRegId = token;
}
void Subscribe (string token)
{
var pubSub = GcmPubSub.GetInstance(this);
pubSub.Subscribe(token, "/topics/global", null);
// TODO if a Activity is specified,
// and general annonces in this activity are accepted:
//
// pubSub.Subscribe(token, "/topics/jobs/"+ActivityCode, null);
}
}
}

View File

@ -0,0 +1,134 @@
using System;
using Android.App;
using Android.OS;
using Android.Content;
using Android.Util;
using Android.Widget;
namespace BookAStar.Droid
{
[Service]
public class MyGcmIntentService : IntentService
{
static PowerManager.WakeLock sWakeLock;
static object LOCK = new object();
public static void RunIntentInService(Context context, Intent intent)
{
lock (LOCK)
{
if (sWakeLock == null)
{
// This is called from BroadcastReceiver, there is no init.
var pm = PowerManager.FromContext(context);
sWakeLock = pm.NewWakeLock(
WakeLockFlags.Partial, "My WakeLock Tag");
}
}
sWakeLock.Acquire();
intent.SetClass(context, typeof(MyGcmIntentService));
context.StartService(intent);
}
static object locker = new object();
protected override void OnHandleIntent(Intent intent)
{
try
{
Log.Info ("MyIntentService", "Calling InstanceID.GetToken");
lock (locker)
{
string action = intent.Action;
if (action!=null)
if (action.Equals("com.google.android.c2dm.intent.REGISTRATION"))
{
HandleRegistration(intent);
}
else if (action.Equals("com.google.android.c2dm.intent.RECEIVE"))
{
HandleMessage(intent);
}
}
}
finally
{
lock (LOCK)
{
//Sanity check for null as this is a public method
if (sWakeLock != null)
sWakeLock.Release();
}
}
}
private void HandleMessage(Intent intent)
{
// get the notification type id:
string ntft = intent.GetStringExtra("type");
string msg = intent.GetStringExtra("Description");
var position = intent.GetSerializableExtra ("Location");
SendNotification (msg);
}
void SendNotification (string message)
{
/* Bundle valuesForActivity = new Bundle();
valuesForActivity.PutInt("count", count); */
var intent = new Intent (this, typeof(MainActivity));
intent.AddFlags (ActivityFlags.ClearTop);
var pendingIntent = PendingIntent.GetActivity (this, 0, intent, PendingIntentFlags.OneShot);
// Construct a back stack for cross-task navigation:
TaskStackBuilder stackBuilder = TaskStackBuilder.Create(this);
stackBuilder.AddParentStack(Java.Lang.Class.FromType(typeof(MainActivity)));
stackBuilder.AddNextIntent(intent);
// Create the PendingIntent with the back stack:
PendingIntent resultPendingIntent =
stackBuilder.GetPendingIntent(0, PendingIntentFlags.UpdateCurrent);
var notificationBuilder = new Notification.Builder(this)
.SetAutoCancel(true)
.SetSmallIcon (Resource.Drawable.icon)
.SetContentTitle ("GCM Message")
.SetContentText (message)
.SetContentIntent(resultPendingIntent) // Start 2nd activity when the intent is clicked.
;
var notificationManager = (NotificationManager) GetSystemService(Context.NotificationService);
notificationManager.Notify (0, notificationBuilder.Build());
}
private void HandleRegistration(Intent intent)
{
string registrationId = intent.GetStringExtra("registration_id");
string error = intent.GetStringExtra("error");
string unregistration = intent.GetStringExtra("unregistered");
}
void SubscribeGCM ()
{
Context context = this.ApplicationContext;
string senders = MainSettings.GoogleSenderId;
// Resources.GetString(GoogleSenderId);
Intent intent = new Intent ("com.google.android.c2dm.intent.REGISTER");
intent.SetPackage ("com.google.android.gsf");
intent.PutExtra ("app", PendingIntent.GetBroadcast (context, 0, new Intent (), 0));
intent.PutExtra ("sender", senders);
context.StartService (intent);
}
void UnsubscribeGCM ()
{
Context context = this.ApplicationContext;
Intent intent = new Intent("com.google.android.c2dm.intent.UNREGISTER");
intent.PutExtra("app", PendingIntent.GetBroadcast(context, 0, new Intent(), 0));
context.StartService (intent);
}
}
}

View File

@ -0,0 +1,18 @@
using System;
using Android.App;
using Android.Gms.Gcm.Iid;
using Android.Content;
namespace BookAStar.Droid
{
[Service(Exported = false), IntentFilter(new[] { "com.google.android.gms.iid.InstanceID" })]
class MyInstanceIDListenerService : InstanceIDListenerService
{
public override void OnTokenRefresh()
{
var intent = new Intent (this, typeof (GcmRegistrationIntentService));
StartService (intent);
}
}
}

View File

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Service.Chooser;
using static Android.Manifest;
namespace BookAStar.Droid
{
[Service(
Name = "fr.pschneider.bas.YavscChooserTargetService",
Label = "Yavsc share service",
Permission = Permission.BindChooserTargetService,
Icon = "@drawable/icon",
Exported = true,
Enabled = true
)]
[IntentFilter(new String[] { "android.service.chooser.ChooserTargetService" })]
class YavscChooserTargetService : ChooserTargetService
{
public override IList<ChooserTarget> OnGetChooserTargets(ComponentName targetActivityName, IntentFilter matchedFilter)
{
Android.Graphics.Drawables.Icon i =
Android.Graphics.Drawables.Icon.CreateWithResource(this.BaseContext,
Resource.Drawable.icon);
ChooserTarget t = new ChooserTarget(
new Java.Lang.String(
Constants.ApplicationName), i,
.5f, new ComponentName(this, "BookAStar.SendFilesActivity"),
null);
var res = new List<ChooserTarget>();
res.Add(t);
return res;
}
public override IBinder OnBind(Intent intent)
{
return base.OnBind(intent);
}
}
}

View File

@ -0,0 +1,564 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{2A8C2BD7-B1B6-4D74-A3FC-3F5DB3BE325E}</ProjectGuid>
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>BookAStar.Droid</RootNamespace>
<AssemblyName>BookAStar.Droid</AssemblyName>
<FileAlignment>512</FileAlignment>
<AndroidApplication>true</AndroidApplication>
<AndroidResgenFile>Resources\Resource.Designer.cs</AndroidResgenFile>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
<AndroidUseLatestPlatformSdk>True</AndroidUseLatestPlatformSdk>
<TargetFrameworkVersion>v7.0</TargetFrameworkVersion>
<AndroidSupportedAbis>armeabi,armeabi-v7a,x86</AndroidSupportedAbis>
<AndroidStoreUncompressedFileExtensions />
<MandroidI18n />
<JavaMaximumHeapSize />
<JavaOptions />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>True</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>0</WarningLevel>
<AndroidUseSharedRuntime>True</AndroidUseSharedRuntime>
<AndroidLinkMode>None</AndroidLinkMode>
<EmbedAssembliesIntoApk>False</EmbedAssembliesIntoApk>
<BundleAssemblies>False</BundleAssemblies>
<AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
<JavaMaximumHeapSize>1100m</JavaMaximumHeapSize>
<Debugger>Xamarin</Debugger>
<AndroidEnableMultiDex>False</AndroidEnableMultiDex>
<CodeAnalysisRuleSet />
<AotAssemblies>False</AotAssemblies>
<EnableLLVM>False</EnableLLVM>
<EnableProguard>False</EnableProguard>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<AndroidLinkMode>None</AndroidLinkMode>
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
<BundleAssemblies>False</BundleAssemblies>
<AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
<JavaMaximumHeapSize>1100m</JavaMaximumHeapSize>
<Debugger>Xamarin</Debugger>
<AotAssemblies>False</AotAssemblies>
<EnableLLVM>False</EnableLLVM>
<AndroidEnableMultiDex>False</AndroidEnableMultiDex>
<EnableProguard>False</EnableProguard>
<DebugSymbols>False</DebugSymbols>
<CodeAnalysisRuleSet />
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Lua|AnyCPU'">
<OutputPath>bin\Lua\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<AndroidUseSharedRuntime>True</AndroidUseSharedRuntime>
<AndroidLinkMode>SdkOnly</AndroidLinkMode>
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
<BundleAssemblies>False</BundleAssemblies>
<AndroidCreatePackagePerAbi>False</AndroidCreatePackagePerAbi>
<JavaMaximumHeapSize>1100m</JavaMaximumHeapSize>
<Debugger>Xamarin</Debugger>
<AotAssemblies>False</AotAssemblies>
<EnableLLVM>False</EnableLLVM>
<AndroidEnableMultiDex>False</AndroidEnableMultiDex>
<EnableProguard>False</EnableProguard>
<DebugSymbols>False</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<Reference Include="ExifLib, Version=1.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\ExifLib.PCL.1.0.1\lib\portable-net45+sl50+win+WindowsPhoneApp81+wp80+Xamarin.iOS10+MonoAndroid10+MonoTouch10\ExifLib.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="FormsViewGroup, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.2.3.2.127\lib\MonoAndroid10\FormsViewGroup.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="GoogleMediaFramework">
<HintPath>..\..\Components\GoogleMediaFramework-1.0\lib\android\GoogleMediaFramework.dll</HintPath>
</Reference>
<Reference Include="MarkdownDeep, Version=1.5.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\MarkdownDeep-av.NET.1.5.2\lib\MonoAndroid10\MarkdownDeep.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\MonoAndroid\v7.0\Mono.Android.dll</HintPath>
</Reference>
<Reference Include="Mono.Android.Export, Version=1.0.6149.16186, Culture=neutral, PublicKeyToken=84e04ff9cfb79065, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\MonoAndroid\v7.0\Mono.Android.Export.dll</HintPath>
</Reference>
<Reference Include="Mono.Data.Sqlite" />
<Reference Include="mscorlib" />
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\portable-net45+wp80+win8+wpa81\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Plugin.Connectivity, Version=2.2.12.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.Connectivity.2.2.12\lib\MonoAndroid10\Plugin.Connectivity.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Plugin.Connectivity.Abstractions, Version=2.2.12.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.Connectivity.2.2.12\lib\MonoAndroid10\Plugin.Connectivity.Abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Plugin.CurrentActivity, Version=1.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Plugin.CurrentActivity.1.0.1\lib\MonoAndroid10\Plugin.CurrentActivity.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Plugin.DeviceInfo, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.DeviceInfo.2.0.2\lib\MonoAndroid10\Plugin.DeviceInfo.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Plugin.DeviceInfo.Abstractions, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.DeviceInfo.2.0.2\lib\MonoAndroid10\Plugin.DeviceInfo.Abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Plugin.Geolocator, Version=3.0.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.Geolocator.3.0.4\lib\MonoAndroid10\Plugin.Geolocator.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Plugin.Geolocator.Abstractions, Version=3.0.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.Geolocator.3.0.4\lib\MonoAndroid10\Plugin.Geolocator.Abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Plugin.Media, Version=2.2.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.Media.2.3.0\lib\MonoAndroid10\Plugin.Media.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Plugin.Media.Abstractions, Version=2.2.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugin.Media.2.3.0\lib\MonoAndroid10\Plugin.Media.Abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Plugin.Permissions, Version=1.1.6.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Plugin.Permissions.1.1.7\lib\MonoAndroid10\Plugin.Permissions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Plugin.Permissions.Abstractions, Version=1.1.6.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Plugin.Permissions.1.1.7\lib\MonoAndroid10\Plugin.Permissions.Abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Plugin.Settings, Version=2.5.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugins.Settings.2.5.1.0\lib\MonoAndroid10\Plugin.Settings.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Plugin.Settings.Abstractions, Version=2.5.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xam.Plugins.Settings.2.5.1.0\lib\MonoAndroid10\Plugin.Settings.Abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Plugin.Share, Version=3.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Plugin.Share.3.0.1\lib\MonoAndroid10\Plugin.Share.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Plugin.Share.Abstractions, Version=3.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Plugin.Share.3.0.1\lib\MonoAndroid10\Plugin.Share.Abstractions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SignaturePad, Version=1.4.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Controls.SignaturePad.1.4.0\lib\MonoAndroid\SignaturePad.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SignaturePad.Forms, Version=1.4.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Controls.SignaturePad.Forms.1.4.0\lib\MonoAndroid\SignaturePad.Forms.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SignaturePad.Forms.Droid, Version=1.4.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Controls.SignaturePad.Forms.1.4.0\lib\MonoAndroid\SignaturePad.Forms.Droid.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLite.Net">
<HintPath>..\..\packages\SQLite.Net.Core-PCL.3.1.1\lib\portable-win8+net45+wp8+wpa81+MonoAndroid1+MonoTouch1\SQLite.Net.dll</HintPath>
</Reference>
<Reference Include="SQLite.Net.Async, Version=3.1.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLite.Net.Async-PCL.3.1.1\lib\portable-win8+net45+wp8+wpa81+MonoAndroid1+MonoTouch1\SQLite.Net.Async.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLite.Net.Platform.XamarinAndroid, Version=2.5.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\SQLite.Net.Platform.XamarinAndroid.2.5.1\lib\MonoAndroid\SQLite.Net.Platform.XamarinAndroid.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5.1\System.Drawing.dll</HintPath>
</Reference>
<Reference Include="System.Json" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Web.Services" />
<Reference Include="Xamarin.Android.Support.Animated.Vector.Drawable, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Android.Support.Animated.Vector.Drawable.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.Animated.Vector.Drawable.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.Android.Support.Design, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Android.Support.Design.23.3.0\lib\MonoAndroid43\Xamarin.Android.Support.Design.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.Android.Support.v4, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Android.Support.v4.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v4.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.AppCompat, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Android.Support.v7.AppCompat.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.AppCompat.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.CardView, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Android.Support.v7.CardView.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.CardView.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.MediaRouter, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Android.Support.v7.MediaRouter.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.MediaRouter.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.Android.Support.v7.RecyclerView, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Android.Support.v7.RecyclerView.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.v7.RecyclerView.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.Android.Support.Vector.Drawable, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\lib\MonoAndroid403\Xamarin.Android.Support.Vector.Drawable.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.Auth.Android">
<HintPath>..\..\Components\xamarin.auth-1.2.3.1\lib\android\Xamarin.Auth.Android.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Core, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.2.3.2.127\lib\MonoAndroid10\Xamarin.Forms.Core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.Forms.Maps, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.Maps.2.3.2.127\lib\MonoAndroid10\Xamarin.Forms.Maps.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.Forms.Maps.Android, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.Maps.2.3.2.127\lib\MonoAndroid10\Xamarin.Forms.Maps.Android.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.Forms.Platform, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.2.3.2.127\lib\MonoAndroid10\Xamarin.Forms.Platform.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.Forms.Platform.Android, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.2.3.2.127\lib\MonoAndroid10\Xamarin.Forms.Platform.Android.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.Forms.Xaml, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.Forms.2.3.2.127\lib\MonoAndroid10\Xamarin.Forms.Xaml.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.GooglePlayServices.Ads, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.GooglePlayServices.Ads.29.0.0.1\lib\MonoAndroid41\Xamarin.GooglePlayServices.Ads.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.GooglePlayServices.Analytics, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.GooglePlayServices.Analytics.29.0.0.1\lib\MonoAndroid41\Xamarin.GooglePlayServices.Analytics.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.GooglePlayServices.Base, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.GooglePlayServices.Base.29.0.0.1\lib\MonoAndroid41\Xamarin.GooglePlayServices.Base.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.GooglePlayServices.Basement, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.GooglePlayServices.Basement.29.0.0.1\lib\MonoAndroid41\Xamarin.GooglePlayServices.Basement.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.GooglePlayServices.Gcm, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.GooglePlayServices.Gcm.29.0.0.1\lib\MonoAndroid41\Xamarin.GooglePlayServices.Gcm.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.GooglePlayServices.Maps, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.GooglePlayServices.Maps.29.0.0.1\lib\MonoAndroid41\Xamarin.GooglePlayServices.Maps.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Xamarin.GooglePlayServices.Measurement, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\Xamarin.GooglePlayServices.Measurement.29.0.0.1\lib\MonoAndroid41\Xamarin.GooglePlayServices.Measurement.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="XLabs.Caching, Version=2.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\XLabs.Caching.2.3.0-pre02\lib\portable-net45+netcore45+wpa81+wp8+monoandroid+monotouch+xamarinios10+xamarinmac\XLabs.Caching.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="XLabs.Caching.Sqlite, Version=2.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\XLabs.Caching.SQLite.2.3.0-pre02\lib\portable-net45+netcore45+wpa81+wp8+monoandroid+monotouch+xamarinios10+xamarinmac\XLabs.Caching.Sqlite.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="XLabs.Core, Version=2.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\XLabs.Core.2.3.0-pre02\lib\portable-net45+netcore45+wpa81+wp8+monoandroid+monotouch+xamarinios10+xamarinmac\XLabs.Core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="XLabs.Forms, Version=2.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\XLabs.Forms.2.3.0-pre02\lib\monoandroid\XLabs.Forms.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="XLabs.Forms.Droid, Version=2.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\XLabs.Forms.2.3.0-pre02\lib\monoandroid\XLabs.Forms.Droid.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="XLabs.IOC, Version=2.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\XLabs.IoC.2.3.0-pre02\lib\portable-net45+netcore45+wpa81+wp8+monoandroid+monotouch+xamarinios10+xamarinmac\XLabs.IOC.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="XLabs.Platform, Version=2.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\XLabs.Platform.2.3.0-pre02\lib\MonoAndroid\XLabs.Platform.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="XLabs.Platform.Droid, Version=2.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\XLabs.Platform.2.3.0-pre02\lib\MonoAndroid\XLabs.Platform.Droid.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="XLabs.Serialization, Version=2.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\XLabs.Serialization.2.3.0-pre02\lib\portable-net45+netcore45+wpa81+wp8+monoandroid+monotouch+xamarinios10+xamarinmac\XLabs.Serialization.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="XLabs.Serialization.Json.NET, Version=2.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\XLabs.Serialization.JSON.2.3.0-pre02\lib\portable-net45+netcore45+wpa81+wp8+monoandroid+monotouch+xamarinios10+xamarinmac\XLabs.Serialization.Json.NET.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="XLabs.Settings, Version=2.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\XLabs.Settings.2.3.0-pre02\lib\portable-net45+netcore45+wpa81+wp8+monoandroid+monotouch+xamarinios10+xamarinmac\XLabs.Settings.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="XLabs.Settings.XamSettings, Version=2.3.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\packages\XLabs.Settings.XamSettings.2.3.0-pre02\lib\portable-net45+netcore45+wpa81+wp8+monoandroid+monotouch+xamarinios10+xamarinmac\XLabs.Settings.XamSettings.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Accounts\YavscAccountAuthenticator.cs" />
<Compile Include="Helpers\Settings.cs" />
<Compile Include="Helpers\SimpleJsonPostMethod.cs" />
<Compile Include="Helpers\YavscHelpers.cs" />
<Compile Include="Html.cs" />
<Compile Include="Interfaces\IGCMessageHandler.cs" />
<Compile Include="MainActivity.cs" />
<Compile Include="Markdown\JsBridgeMarkdown.cs" />
<Compile Include="Markdown\MarkdownEditor.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>MarkdownEditor.cshtml</DependentUpon>
</Compile>
<Compile Include="Markdown\MarkdownViewModel.cs" />
<Compile Include="Markdown\MarkdownViewRenderer.cs" />
<Compile Include="Markdown\MarkdownWebChromeClient.cs" />
<Compile Include="Markdown\MDContextMenu.cs" />
<Compile Include="Markdown\MDWebView.cs" />
<Compile Include="OAuth2\YaOAuth2Authenticator.cs" />
<Compile Include="Rendering\ImageButtonRenderer.cs" />
<Compile Include="Resources\Resource.Designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SendFilesActivity.cs" />
<Compile Include="Services\AccountChooserService.cs" />
<Compile Include="Services\GCMHandlers\BookQueryGCMHandler.cs" />
<Compile Include="Services\GCMHandlers\EstimateGCMHandler.cs" />
<Compile Include="Services\GCMHandlers\GCMessageHandler.cs" />
<Compile Include="Services\YavscChooserTargetService.cs" />
<Compile Include="Services\GcmListenerService.cs" />
<Compile Include="Services\GcmRegistrationIntentService.cs" />
<Compile Include="Services\MyGcmIntentService.cs" />
<Compile Include="Services\MyInstanceIdListener.cs" />
<Compile Include="CompatXFormsApp.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config">
<SubType>Designer</SubType>
</None>
<None Include="google-services.json" />
<None Include="Markdown\MarkdownEditor.cshtml">
<Generator>RazorTemplatePreprocessor</Generator>
<LastGenOutput>MarkdownEditor.cs</LastGenOutput>
<SubType>None</SubType>
</None>
<None Include="packages.config">
<SubType>Designer</SubType>
</None>
<None Include="Resources\AboutResources.txt" />
<AndroidAsset Include="Assets\AboutAssets.txt" />
<AndroidResource Include="Resources\layout\EditEstimate.axml">
<SubType>Designer</SubType>
</AndroidResource>
<AndroidResource Include="Resources\menu\md_menu.axml">
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\icon.png" />
</ItemGroup>
<ItemGroup>
<None Include="Properties\AndroidManifest.xml" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\layout\Tabbar.axml" />
<AndroidResource Include="Resources\layout\Toolbar.axml">
<SubType>Designer</SubType>
</AndroidResource>
<AndroidResource Include="Resources\values\styles.xml">
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\YavscLib\YavscLib.csproj">
<Project>{67f9d3a8-f71e-4428-913f-c37ae82cdb24}</Project>
<Name>YavscLib</Name>
</ProjectReference>
<ProjectReference Include="..\ZicMoove\ZicMoove.csproj">
<Project>{A0815650-0A0A-47B0-8826-771F0E1AD137}</Project>
<Name>ZicMoove</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<XamarinComponentReference Include="ConnectivityPlugin">
<Visible>False</Visible>
<Version>1.0.3</Version>
</XamarinComponentReference>
<XamarinComponentReference Include="DeviceInfoPlugin">
<Visible>False</Visible>
<Version>1.0.0.2</Version>
</XamarinComponentReference>
<XamarinComponentReference Include="GeolocatorPlugin">
<Visible>False</Visible>
<Version>1.0.3</Version>
</XamarinComponentReference>
<XamarinComponentReference Include="GoogleMediaFramework">
<Visible>False</Visible>
<Version>1.0</Version>
</XamarinComponentReference>
<XamarinComponentReference Include="googleplayservices">
<Visible>False</Visible>
<Version>22.0.0.0</Version>
</XamarinComponentReference>
<XamarinComponentReference Include="googleplayservices-appinvite">
<Visible>False</Visible>
<Version>29.0.0.2</Version>
</XamarinComponentReference>
<XamarinComponentReference Include="json.net">
<Visible>False</Visible>
<Version>7.0.1</Version>
</XamarinComponentReference>
<XamarinComponentReference Include="MediaPlugin">
<Visible>False</Visible>
<Version>1.0.1</Version>
</XamarinComponentReference>
<XamarinComponentReference Include="SettingsPlugin">
<Visible>False</Visible>
<Version>1.5.2</Version>
</XamarinComponentReference>
<XamarinComponentReference Include="SharePlugin">
<Visible>False</Visible>
<Version>3.0.1</Version>
</XamarinComponentReference>
<XamarinComponentReference Include="signature-pad">
<Visible>False</Visible>
<Version>1.4.0.0</Version>
</XamarinComponentReference>
<XamarinComponentReference Include="xamandroidsupportv4-18">
<Visible>False</Visible>
<Version>23.4.0.1</Version>
</XamarinComponentReference>
<XamarinComponentReference Include="xamandroidsupportv7appcompat">
<Visible>False</Visible>
<Version>24.2.1.0</Version>
</XamarinComponentReference>
<XamarinComponentReference Include="xamarin.auth">
<Visible>False</Visible>
<Version>1.2.3.1</Version>
</XamarinComponentReference>
</ItemGroup>
<ItemGroup>
<AndroidAsset Include="Assets\bootstrap.js" />
<AndroidAsset Include="Assets\jquery.js" />
<AndroidAsset Include="Assets\jquery-ui.js" />
<AndroidAsset Include="Assets\md-helpers.js" />
<AndroidAsset Include="Assets\quill.js" />
<AndroidAsset Include="Assets\showdown.js" />
<AndroidAsset Include="Assets\to-markdown.js" />
<AndroidAsset Include="Assets\quill.snow.css" />
<AndroidAsset Include="Assets\highlight.min.js" />
<AndroidAsset Include="Assets\katex.min.js" />
<AndroidAsset Include="Assets\katex.min.css" />
<AndroidAsset Include="Assets\monokai-sublime.min.css" />
<AndroidAsset Include="Assets\quill.min.js" />
<AndroidAsset Include="Assets\quill.core.css" />
<AndroidAsset Include="Assets\quill.bubble.css" />
<AndroidResource Include="Resources\values\colors.xml">
<SubType>Designer</SubType>
</AndroidResource>
<AndroidResource Include="Resources\values\dimens.xml" />
<AndroidResource Include="Resources\values\strings.xml">
<SubType>Designer</SubType>
</AndroidResource>
<AndroidResource Include="Resources\drawable\glyphish_07_map_marker.png" />
<AndroidResource Include="Resources\drawable\glyphish_13_target.png" />
<AndroidResource Include="Resources\drawable\glyphish_74_location.png" />
<AndroidResource Include="Resources\drawable\glyphish_103_map.png" />
<AndroidResource Include="Resources\drawable\ic_corp_icon.png" />
<AndroidResource Include="Resources\drawable\nfqrcode.png" />
<AndroidResource Include="Resources\drawable\visuel_sexion.jpg" />
<AndroidResource Include="Resources\values\values-21\styles.xml" />
<AndroidResource Include="Resources\drawable\icon_anon.png" />
</ItemGroup>
<ItemGroup>
<Folder Include="Resources\drawable-hdpi\" />
<Folder Include="Resources\drawable-xhdpi\" />
<Folder Include="Resources\drawable-xxhdpi\" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\chat_icon_s.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\exclam.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\drawable\peer_to_peer.png" />
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\xml\authenticator.xml">
<SubType>Designer</SubType>
</AndroidResource>
</ItemGroup>
<ItemGroup>
<AndroidResource Include="Resources\xml\account_preferences.xml" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>Ce projet fait référence à des packages NuGet qui sont manquants sur cet ordinateur. Utilisez l'option de restauration des packages NuGet pour les télécharger. Pour plus d'informations, consultez http://go.microsoft.com/fwlink/?LinkID=322105. Le fichier manquant est : {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets'))" />
<Error Condition="!Exists('..\..\packages\Xamarin.Forms.2.3.2.127\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\packages\Xamarin.Forms.2.3.2.127\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets'))" />
</Target>
<Import Project="..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets" Condition="Exists('..\..\packages\Xamarin.Android.Support.Vector.Drawable.23.3.0\build\Xamarin.Android.Support.Vector.Drawable.targets')" />
<Import Project="..\..\packages\Xamarin.Forms.2.3.2.127\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets" Condition="Exists('..\..\packages\Xamarin.Forms.2.3.2.127\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Drawing" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Data.SqlXml" publicKeyToken="B77A5C561934E089" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Configuration" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Security" publicKeyToken="B03F5F7F11D50A3A" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Xml" publicKeyToken="B77A5C561934E089" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Drawing" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="XLabs.Serialization" publicKeyToken="d65109b36e5040e4" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.0.5782.15703" newVersion="2.0.5782.15703" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View File

@ -0,0 +1,78 @@
{
"project_info": {
"project_number": "325408689282",
"project_id": "yavsc-001"
},
"client": [
{
"client_info": {
"android_client_info": {
"package_name": "fr.pschneider.android.wearable.speedtracker"
}
},
"oauth_client": [
{
"client_id": "325408689282-6bekh7p3guj4k0f3301a6frf025cnrk1.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyBCAE_pc6lrxLf8_Vyho0KSxLsqjxecPFk"
}
],
"services": {
"analytics_service": {
"status": 1
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"ads_service": {
"status": 1
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:325408689282:android:50a2328516f10af3",
"android_client_info": {
"package_name": "fr.pschneider.bas"
}
},
"oauth_client": [
{
"client_id": "325408689282-emdeucmt5pr9jg7170t0q9gnndacsqqf.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "fr.pschneider.bas",
"certificate_hash": "E97A345457861B8E2E7BA79BB814BB1ACC0471A6"
}
},
{
"client_id": "325408689282-6bekh7p3guj4k0f3301a6frf025cnrk1.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyBCAE_pc6lrxLf8_Vyho0KSxLsqjxecPFk"
}
],
"services": {
"analytics_service": {
"status": 1
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"ads_service": {
"status": 1
}
}
}
],
"configuration_version": "1"
}

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="ExifLib.PCL" version="1.0.1" targetFramework="monoandroid70" />
<package id="MarkdownDeep-av.NET" version="1.5.2" targetFramework="monoandroid60" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="monoandroid60" />
<package id="Plugin.CurrentActivity" version="1.0.1" targetFramework="monoandroid70" />
<package id="Plugin.Permissions" version="1.1.7" targetFramework="monoandroid70" />
<package id="Plugin.Share" version="3.0.1" targetFramework="monoandroid70" />
<package id="SQLite.Net.Async-PCL" version="3.1.1" targetFramework="monoandroid70" />
<package id="SQLite.Net.Core-PCL" version="3.1.1" targetFramework="monoandroid70" />
<package id="SQLite.Net.Platform.XamarinAndroid" version="2.5.1" targetFramework="monoandroid70" />
<package id="SQLite.Net-PCL" version="3.1.1" targetFramework="monoandroid70" />
<package id="Xam.Plugin.Connectivity" version="2.2.12" targetFramework="monoandroid70" />
<package id="Xam.Plugin.DeviceInfo" version="2.0.2" targetFramework="monoandroid70" />
<package id="Xam.Plugin.Geolocator" version="3.0.4" targetFramework="monoandroid70" />
<package id="Xam.Plugin.Media" version="2.3.0" targetFramework="monoandroid70" />
<package id="Xam.Plugins.Settings" version="2.5.1.0" targetFramework="monoandroid70" />
<package id="Xamarin.Android.Support.Animated.Vector.Drawable" version="23.3.0" targetFramework="monoandroid60" />
<package id="Xamarin.Android.Support.Design" version="23.3.0" targetFramework="monoandroid60" />
<package id="Xamarin.Android.Support.v4" version="23.3.0" targetFramework="monoandroid60" />
<package id="Xamarin.Android.Support.v7.AppCompat" version="23.3.0" targetFramework="monoandroid60" />
<package id="Xamarin.Android.Support.v7.CardView" version="23.3.0" targetFramework="monoandroid60" />
<package id="Xamarin.Android.Support.v7.MediaRouter" version="23.3.0" targetFramework="monoandroid60" />
<package id="Xamarin.Android.Support.v7.RecyclerView" version="23.3.0" targetFramework="monoandroid60" />
<package id="Xamarin.Android.Support.Vector.Drawable" version="23.3.0" targetFramework="monoandroid60" />
<package id="Xamarin.Controls.SignaturePad" version="1.4.0" targetFramework="monoandroid70" />
<package id="Xamarin.Controls.SignaturePad.Forms" version="1.4.0" targetFramework="monoandroid70" />
<package id="Xamarin.Forms" version="2.3.2.127" targetFramework="monoandroid70" />
<package id="Xamarin.Forms.Maps" version="2.3.2.127" targetFramework="monoandroid70" />
<package id="Xamarin.GooglePlayServices.Ads" version="29.0.0.1" targetFramework="monoandroid70" />
<package id="Xamarin.GooglePlayServices.Analytics" version="29.0.0.1" targetFramework="monoandroid70" />
<package id="Xamarin.GooglePlayServices.Base" version="29.0.0.1" targetFramework="monoandroid70" />
<package id="Xamarin.GooglePlayServices.Basement" version="29.0.0.1" targetFramework="monoandroid70" />
<package id="Xamarin.GooglePlayServices.Gcm" version="29.0.0.1" targetFramework="monoandroid70" />
<package id="Xamarin.GooglePlayServices.Maps" version="29.0.0.1" targetFramework="monoandroid70" />
<package id="Xamarin.GooglePlayServices.Measurement" version="29.0.0.1" targetFramework="monoandroid70" />
<package id="XLabs.Caching" version="2.3.0-pre02" targetFramework="monoandroid70" />
<package id="XLabs.Caching.SQLite" version="2.3.0-pre02" targetFramework="monoandroid70" />
<package id="XLabs.Core" version="2.3.0-pre02" targetFramework="monoandroid70" />
<package id="XLabs.Forms" version="2.3.0-pre02" targetFramework="monoandroid70" />
<package id="XLabs.IoC" version="2.3.0-pre02" targetFramework="monoandroid70" />
<package id="XLabs.Platform" version="2.3.0-pre02" targetFramework="monoandroid70" />
<package id="XLabs.Serialization" version="2.3.0-pre02" targetFramework="monoandroid70" />
<package id="XLabs.Serialization.JSON" version="2.3.0-pre02" targetFramework="monoandroid70" />
<package id="XLabs.Settings" version="2.3.0-pre02" targetFramework="monoandroid70" />
<package id="XLabs.Settings.XamSettings" version="2.3.0-pre02" targetFramework="monoandroid70" />
</packages>