Share multiple items (PDF's) with ShareLink and Transferable in SwiftUI - swiftui

I want to share multiple PDF Documents with apples new ShareLink.
I can share a single PDF Document by making my object transferable using the FileReprestation and giving my object into shareLink:
extension item: Transferable {
public static var transferRepresentation: some TransferRepresentation {
FileRepresentation(exportedContentType: .pdf) { item in
return SentTransferredFile(item.url, allowAccessingOriginalFile: false)
}
}
}
and using ShareLink in my view:
ShareLink(item: item, preview: SharePreview(Text(""))) {
Label("",systemImage: "square.and.arrow.up")
}
Another working option is giving ShareLink the URL of my PDF.
Now I want to share multiple PDF docs at the same time. I have an Array of Items ([Item]). Sadly ShareLink does not take and array of objects as input...
How can I solve the problem?

Related

SwiftUI sectioned list with large data set is sluggish

I am trying to create a sections list of a large data set, 20,000 plus records, but this applies for even lower data sets of 5k records,
I have looked at
https://www.raywenderlich.com/27201015-dynamic-core-data-with-swiftui-tutorial-for-ios
and it works fine for a small data set of 20 records but once I add more data by editing this function to create more records
private func addTestFriends() {
let request = Friend.fetchRequest()
let context = PersistenceManager.shared.persistentContainer.viewContext
do {
if try context.count(for: request) == 0 {
for number in 1...1000 {
print(number)
try Friend.generateTestFriends(in: context)
}
}
} catch {
print("Error generating friends: \(error)")
}
}
Which results in 20,000 records the app is really really sluggish, just closing the sections with the disclosure is slow.
Is this a flaw in SwiftUI or is there a different approach?
I also looked at Apples
https://developer.apple.com/documentation/swiftui/loading_and_displaying_a_large_data_feed
which when doing a flat fetch of 10,000+ earth quakes loads fine, but once I try to section it
#SectionedFetchRequest(sectionIdentifier: \.code, sortDescriptors: [SortDescriptor(\.time, order: .reverse)], animation: .default)
private var quakes2: SectionedFetchResults<String, Quake>
sectioning it by "code" and it takes agessssss to load and then again is slugish
This seems a major flaw if you cannot create sections for large data sets of more that 1000 records

What is the difference between `FileDocument` and `ReferenceFileDocument` for `DocumentGroups` in SwiftUI?

I'm trying to setup a DocumentGroup in my app, but there's no examples out there yet ReferenceFileDocument is for. I know what a FileDocument is, but how are ReferenceFileDocuments different.
In the docs all it says is:
Conformance to ReferenceFileDocument is expected to be thread-safe,
and deserialization and serialization will be done on a background
thread.
There's a hint in the name: ReferenceFileDocument is a document that's a reference type (ie, a class). FileDocument is for a struct based document.
This has an effect on how documents are saved because SwiftUI can just make a copy of the reference type and save it without worrying about you coming along and modifying it during the save, since it's a value type or tree of value types.
With ReferenceFileDocument, there also doesn't seem to be a clear way for the SwiftUI to know when to save, so it depends on you telling it. There's no direct "doc is dirty, save it now" method, so the way you inform SwiftUI that you've done something that requires saving is through the undo manager.
You also need to provide a snapshot method to return a copy of the document that's safe for it to save.
final class QuizDocument: ReferenceFileDocument, ObservableObject {
#Published var quiz: QuizTemplate
init(quiz: QuizTemplate) {
self.quiz = quiz
}
static var readableContentTypes: [UTType] { [.exampleText] }
init(configuration: ReadConfiguration) throws {
guard let data = configuration.file.regularFileContents,
let quiz = try? JSONDecoder().decode(QuizTemplate.self, from: data)
else {
throw CocoaError(.fileReadCorruptFile)
}
self.quiz = quiz
}
// Produce a snapshot suitable for saving. Copy any nested references so they don't
// change while the save is in progress.
func snapshot(contentType: UTType) throws -> QuizTemplate {
return self.quiz
}
// Save the snapshot
func fileWrapper(snapshot: QuizTemplate, configuration: WriteConfiguration) throws -> FileWrapper {
let data = try JSONEncoder().encode(quiz)
return .init(regularFileWithContents: data)
}
}
ReferenceFileDocument is a document type that will auto-save in the background. It is notified of changes via the UndoManager, so in order to use it you must also make your document undo-able.
The only mention I see of it in the docs is here.
Here is a working example.

Color Status indicator in O365 SharePoint Online

I am working with O365 SharePoint Online platform with SharePoint lists around 300 items in All Items View. For the first 30 items Text to Html Javascript function successfully converts text code to Html and displays status in HTML color format, but when I am trying to select next 31 items and go ahead using the pagination the function does not able to convert Html and display only text codes. I also changed the calculated column value type to "Number" to get the HTML to render in the list view. But not being changed yet. Does anyone please who have the code handy to make this work easy? Below is the Text to HTML code used in O365 platform.
<script type="text/javascript">
function TextToHTML(NodeSet, HTMLregexp) {
var CellContent = "";
var i=0;
while (i < NodeSet.length){
try {
CellContent = NodeSet[i].innerText || NodeSet[i].textContent;
if (HTMLregexp.test(CellContent)) {NodeSet[i].innerHTML = CellContent;}
}
catch(err){}
i=i+1;
}
}
// Calendar views
var regexpA = new RegExp("\\s*<([a-zA-Z]*)(.|\\s)*/\\1?>\\s*");
TextToHTML(document.getElementsByTagName("a"),regexpA);
// List views
var regexpTD = new RegExp("^\\s*<([a-zA-Z]*)(.|\\s)*/\\1?>\\s*$");
TextToHTML(document.getElementsByTagName("TD"),regexpTD);
// This function is call continuesly every 100ms until the length of the main field changes
// after which the convert text to HTML is executed.
//
var postElemLength = 0;
function PostConvertToHtml()
{
if (postElemLength == document.getElementsByTagName("TD").length)
{
setTimeout(PostConvertToHtml,100);
}
else
{
var regexpTD = new RegExp("^\\s*<([a-zA-Z]*)(.|\\s)*/\\1?>\\s*$");
TextToHTML(document.getElementsByTagName("TD"),regexpTD);
}
}
// Grouped list views
ExpGroupRenderData = (function (old) {
return function (htmlToRender, groupName, isLoaded) {
var result = old(htmlToRender, groupName, isLoaded);
var regexpTD = new RegExp("^\\s*<([a-zA-Z]*)(.|\\s)*/\\1?>\\s*$");
TextToHTML(document.getElementsByTagName("TD"),regexpTD);
// start the periodic callback to check when the element has been changed
if(isLoaded == 'false')
{
postElemLength = document.getElementsByTagName("TD").length;
setTimeout(PostConvertToHtml,100);
}
};
})(ExpGroupRenderData);
// Preview pane views
if (typeof(showpreview1)=="function") {
showpreview1 = (function (old) {
return function (o) {
var result = old(o);
var regexpTD = new RegExp("^\\s*<([a-zA-Z]*)(.|\\s)*/\\1?>\\s*$");
TextToHTML(document.getElementsByTagName("TD"),regexpTD);
};
})(showpreview1);
}</script>
Below is the generated text code which needs to be converted to Html used in calculated columns. Thanks.
=IF([Trend]="Cancelled","DarkGray",IF([Trend]="Completed","DodgerBlue",IF([Trend]="Declining","DarkOrange",IF([Trend]="Improving","ForestGreen",IF([Trend]="No Change","ForestGreen",IF([Trend]="Not Started","White",IF([Trend]="On Hold","DarkGray","")))))))
And..
="<div style='position:relative;display:inline-block;width:100%;'>
<div style='width:100%;display:inline-block;text-align:center;border:1px solid "&[VPN provisioning_Clr]&";position:absolute;color:"&[VPN provisioning_Clr]&";'> "&[VPN provisioning]&"
</div>
<div style='display:inline-block;width: 100%;background-color:"&[VPN provisioning_Clr]&";text-align:center;border:1px solid;z-index:-1;filter:alpha(opacity=20);opacity:0.2;'>"&[VPN provisioning]&"
</div>
</div>"
Assuming you are using the Classic UI in SharePoint Online...
Two possible issues:
Check to see if the site has the Minimal Download Strategy enabled.
If so disable it and test your code. MDS often is the cause for JavaScript running only once. (The page is not reloaded, only the data area.)
The loading of the next page of the list is via a Web Service call and that may not be triggering your JavaScript. (Again, the page is not reloaded, only the data area.) You may need to intercept the paging link to insure your code is run. (Also check to see if the "Asynchronous Load" option has been enabled. Edit the page, edit the web part, and expand the "AJAX Options" section.)
You may want to take a look at a workflow plus a Calculated column solution to add the color coding. See: http://techtrainingnotes.blogspot.com/2018/01/adding-html-to-sharepoint-columns-color.html

How to get from CouchDB only certain fields of certain documents with a single request?

create a view that return only a subset of values from a document, each with its key and value within a json string. like if one given view returns a document as this following, Is it possible to get some fields information for a one request? thank you
{
"total_rows":10,
"offset":3,
"rows":[{
"id":"doc1",
"key":"abc123",
"value": {
"_id":"aaaa",
"_rev":"bbb",
"field1":"abc",
"field2":"bcd",
"field3":"cde",
"field4":"123",
"field5":"789",
"field6":"aa#email.com",
"field7":"ttt",
"field8":"iii",
"field9":[{
"field91":"tyui",
"field92":"55555"
}],
"field10"::"0000",
"field11"::"55555",
"field12"::"0030".........
}
}
I just want to create a view that returns some fields only the following:
{
"field1":"abc",
"field2":"bcd",
"field3":"cde",
"field4":"123",
"field5":"789",
"field6":"aa#email.com",
"field7":"ttt",
"field8":"iii",
"field9":[{
"field91":"tyui",
"field92":"55555"
}]
}
A map function that emits a new document with selected fields only. As an example, let's map field1 (a string) and field9 (an array) only:
function map(doc) {
emit(doc._id, {
field1: doc.field1,
field9: doc.field9
});
}
In the above example, each document will be fired with a key being the original doc ID and the value being the mapped fields you require.
This is useful if you are planning to add a reduce function later.
Depending on your use case, you may just want to emit the mapped objects:
function map(doc) {
emit({
field1: doc.field1,
field9: doc.field9
});
}
Please see http://guide.couchdb.org/draft/views.html
The documentation on building data views is pretty good, you can discover a lot by experimenting..

How do I add custom column to existing WSS list template

I need to use feature stapler to add some text columns to Posts list inside OOTB blog site definition. I plan not to use site columns, but only to add those columns to list (I don't use site columns because I have multiple site collections and there will be only one Posts list per site collection, so site columns are not very reusable in this case). My question is: How do I achieve this?
Perhaps you can create a feature that uses the object model from the feature receiver to add (and remove as appropriate) the columns to just the specific list when the feature is activated.
I would use the XML Schema approach for creating the columns in order to ensure the same GUID for each column. See
The best solution is to create a hidden custom action for Posts List. I'm posting a simplified version here
Elements.xml:
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomAction Id="XXXXXXXX"
RegistrationType="List"
RegistrationId="101"
Rights="Open"
Location="ViewToolbar"
Sequence="110"
Title="Hidden Settings Button"
ControlAssembly="MyLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=XXXXXX"
ControlClass="MyLib.MyClass"
/>
<FeatureSiteTemplateAssociation Id="XXXXXXX" TemplateName="YOUR_BLOG_SITE_TEMPLATE_NAME" />
MyClass.cs:
[DefaultProperty("Text")]
[ToolboxData("<{0}:MyClass runat=server></{0}:MyClass>")]
public class MyClass : WebControl
{
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string Text
{
get
{
String s = (String)ViewState["Text"];
return ((s == null) ? String.Empty : s);
}
set
{
ViewState["Text"] = value;
}
}
protected override void OnLoad(EventArgs e)
{
SPList list = SPContext.Current.List;
if (list != null)
{
list.Fields.Add(XXX, XXX, XXX);
list.Update();
}
}
}
I cannot see what benefit I have from creating custom action for posts list. Both posts are helpful, but I'll probably create custom feature for that.