'How to apply/enable SwiftUI's 'NavigationLink' only on last child node of fetched nested json instead of all the child nodes?
I've been working to show fetched nested json data(locally stored books).
What i want to achieve:
As the data is of books(different books have different levels of sub chapters/'childs') , i want to show the data in nested chapters and its sub chapters in disclosure-group/outline-group. The last child/node has description which i want to navigate to new view. Rest of the nodes have title names.
What is the current issue
As you can see below. The NavigationLink gets shown in all the child nodes instead of only showing on last node which in json data "child" = null and "type" = content
What i have tried:
1.I tried using separate structure that parse the json data in nested data in outline group.
2.Used .disabled(), .hidden() but it disables 'Navigation-link' on all the child nodes.
3.Used ForEach instead of List.
struct ContentView: View {
@EnvironmentObject var booksList:BooksList
@State var books: [BookModel] = []
@State var selection: BookModel?
@State var isExpandedActive = false
var body: some View {
VStack{
List(booksList.books) { book in
if #available(iOS 15.0, *) {
DisclosureGroup ("\(Text(book.bukTitle!) .fontWeight(.medium) .font(.system(size: 27)))"){
ForEach(book.bookContent ?? []) { bookContent in
DisclosureGroup("\(Text(bookContent.title).fontWeight(.light) .font(.system(size: 25)))")
{
OutlineGroup(bookContent.child , children: \.child) { item in
if #available(iOS 15, *) {
Text(attributedString(from: item.title, font: Font.system(size: 23) ))
.navigationTitle(Text(bookContent.title))
// if (([Child].self as? NSNull) == nil) {
NavigationLink(destination: ScrollView {Text(attributedString(from: item.title, font: Font.system(size: 25) )).padding(30) .lineSpacing(10) .navigationTitle(Text(bookContent.title)) .navigationBarTitleDisplayMode(.inline)
})
{
EmptyView()
.navigationTitle(Text(item.title))
}
}
}
}
}
}
}
}
}
}
The Raw JSON snippet upto title 4.. it has 100s of similar title in nest.. but for just example closing braces accordingly..
[{
"book_title": "સત્સંગિજીવન સાગર મંથન",
"is_live": false,
"user_can_copy": true,
"book_content": [{
"title": "સત્સંગિજીવન માહાત્મ્ય",
"type": "title",
"child": [{
"title": "૦૧. પૂર્વભૂમિકા",
"type": "title",
"child": [{
"title": "૦૧. મંગલાચરણ",
"type": "title",
"child": [{
"title": "<p>સતતં નિજમૂર્તિ ચિન્તકાનામ્, અધિક શ્વેત મનોહર પ્રકાશે ।<br />હૃદિ દર્શિત રમ્ય દિવ્યરૂપં, ભગવન્તં તમહં હરિં નમામિ ।।</p><h3 style='text-align: center;'><strong>( </strong><strong>અર્થ</strong><strong> )</strong></h3><p style='text-align: justify;'> “હંમેશાં પોતાની મૂર્તિનું ચિંતન કરનારા, ભક્તજનોના હૃદય કમળમાં જણાતા અત્યંત શ્વેત મનોહર પ્રકાશવાળા, અક્ષર બ્રહ્મમાં જેમણે બતાવ્યું છે દિવ્યરૂપ એવા ભગવાન શ્રીહરિને હું નમસ્કાર કરું છું.”</p><p style='text-align: justify;'> અનંતકોટિ બ્રહ્માંડોના ઉત્પત્તિના કારણ તથા અનંત ઐશ્વર્ય યુક્ત એવા પૂર્ણપુરુષોત્તમ શ્રી સ્વામિનારાયણ મહાપ્રભુજી તથા આપણા (ઉદ્ધવ) સંપ્રદાયના આદ્ય સ્થાપક ઉદ્ધવાવતાર શ્રી રામાનંદસ્વામી તથા જેની શિષ્ય પરંપરાગતમાં મને શિષ્ય બનવાનો સુલભ અવસર પ્રાપ્ત થયો છે, જેઓને ખુદ સ્વામિનારાયણ ભગવાન ગુરુ તરીકે માનીને મર્યાદા રાખતા અને જેઓને સત્સંગની 'મા' તરીકેનું બિરુદ આપી શ્રીહરિજીએ બહુમાન કર્યું હતું, એવા સર્વગુણે સંપન્ન મારા આદિ ગુરુ સદ્ગુરુ શ્રી મુક્તાનંદ સ્વામી તથા મૂળ અક્ષરમૂર્તિ યોગીરાજ સદ્ગુરુ ગોપાળાનંદ સ્વામી તથા જેઓને ખુદ શ્રીજી મહારાજે પોતાને સ્થાને બેસાડી સંપ્રદાયની ધુરા સોંપી આચાર્યપદ અર્પણ કર્યું છે એવા, સંતોનો અપાર મહિમા સમજનારા અને ગૃહસ્થાશ્રમમાં હોવા છતાં નિષ્કામી વ્રતને ધારણ કરનાર એવા પ. પૂ. ધ. ધુ. ૧૦૦૮ આચાર્ય શ્રી રઘુવીરજી મહારાજ તથા ધ્યાનના અંગવાળા અને આત્મનિષ્ઠાને સાંગોપાંગ જીવનમાં ઉતારનારા પ.પૂ.ધ.ધુ.૧૦૦૮ આચાર્યશ્રી અયોધ્યાપ્રસાદજી મહારાજ તથા સર્વે મહાન સંતો અને મહાન ભક્તોના ચરણોમાં વંદના કરી 'ગ્રંથરાજ શ્રીમદ્ સત્સંગિજીવન' માંથી મારી અલ્પમતિ અનુસાર મંથન કરી સાર રૂપ ઘી શોધવા માટે જઇ રહ્યો છું.</p>",
"type": "content",
"child": null
}]
},
{
"title": "૦૨. ભારતની દુર્દશા",
"type": "title",
"child": [{
"title": "<p style='text-align: justify;'> હે વહાલા ભક્તો ! બસો વર્ષ પહેલાં અઢારમાં સૈકામાં અંધાધૂંધી અતિ ચાલી રહી હતી. ભક્તિના નામે ભ્રષ્ટાચાર, ધર્મના નામે ધતિંગ અને જ્ઞાનના ગુમાનમાં મસ્ત બની ધર્મગુરુઓ ભોળા મુમુક્ષુઓને છેતરતા હતા.<br /> વૈરાગ્યની કેવળ વાતો કરીને વૈરાગીઓ વિલાસી બની ગયા હતા. વિદ્વાનો સત્શાસ્ત્રોના અવળા અર્થો કરીને લોકોને ભરમાવી રહ્યા હતા. દુષ્ટોનું ચારેબાજુ જોર વધી રહ્યું હતું. રાજાઓ અન્યાયી થઇ ગયા હતા, તેઓ પ્રજાની દાદ-ફરિયાદ સાંભળતા ન હતા. ચોર-લૂંટારાઓનો ત્રાસ સર્વત્ર વ્યાપી ગયો હતો. નિર્દોષ નાની બાલિકાઓને દૂધ પીતી કરવાના નિમિષે ક્રૂરપણે દૂધમાં ડૂબાડી મારી નાખવામાં આવતી હતી. પતિ મૃત્યુ પામે તો તેની પાછળ તેમની પત્નીઓને પરાણે પકડીને ચિતામાં બેસાડી જીવતી સળગાવી દેવામાં આવતી હતી. નિર્દોષ પશુઓને યજ્ઞના નામે મારવામાં આવતા હતા. પોતાની રસ લોલુપતાને કારણે દારુ-માંસનું નૈવદ્ય, દેવ-દેવીઓ આગળ કરવામાં આવતું હતું. ભેખમાં ભગવાન રહેલા છે આવું સમજાવી ભોળી સ્ત્રીઓને પોતાનો મહિમા સમજાવી વામમાર્ગીઓ અને ધર્મગુરુઓ શીયળભ્રષ્ટ કરી વ્યભિચાર કરતા હતા.<br /> સત્તાની સાઠમારીમાં લોકોના જીવ અધ્ધર રહેતા અને 'સૂંડલે ઉચાળા' જેવી તેમની સ્થિતિ હતી. રાજકીય, આર્થિક કે સામાજીક ક્ષેત્રે સમગ્ર ભારતનું ચિત્ર ધૂંધળું હતું.<br /> ગુજરાત અને સૌરાષ્ટ્રની ભૂમિમાં તો કેર વર્તી રહ્યો હતો. કર્નલ વોકર ઇ. સ. ૧૮૦૭ માં સૌરાષ્ટ્રમાં આવ્યા ત્યારે સારાયે સૌરાષ્ટ્રમાં અંધાધૂંધી અને અરાજકતા વ્યાપેલાં હતાં. દર વર્ષે ખંડણી ઉઘરાવવા આવતા મરાઠા લશ્કરો ખુલ્લેઆમ લૂંટ ચલાવતા હતા. ('હિસ્ટરી ઓફ કાઠિયાવાડ'ના આધારે)<br /> ધાર્મિક ક્ષેત્રે પણ ભારતની દુર્દશા ઓછી ન હતી. આજ સમયમાં સંન્યાસીઓ પ્રજાને માર્ગદર્શન આપવાને બદલે પ્રજા ઉપર આફતોનો વરસાદ વરસાવતા હતા. ભારતની ભોળી, અજ્ઞાન અને વ્હેમીપ્રજા તેમનામાં ગુરુભાવ રાખી, તેમની પાસેથી અર્થ અને કામની આશા સેવી તેમની જંગાલિયતને પોષતી હતી. આ જમાતનો ઇતિહાસ વિચિત્ર છે. ઠેઠ કાબૂલથી માંડીને તિબેટ ના દક્ષિણ ભાગ સુધીના પ્રદેશ ઉપર જાણે તેમણે સત્તા જમાવી હોય તેવું લાગતું હતું. તે બાવાઓ ગામડાઓમાંથી અને શહેરોમાંથી તંદુરસ્ત બાળકોનું અપહરણ કરીને પોતાના શિષ્યો બનાવતા હતા. તથા જાત્રાને બહાને ગામોગામ ફરતા હતા. (ધી સંન્યાસિસ ઓફ મૈમનસિંહ ' પા.-૨૨)<br /> વૈદિક ધર્મના તમામ નિયમોને અવગણિને મદ્ય, માંસ અને મૈથુનમાં સૌ આસક્ત બની ગયા હતા. વામ માર્ગ, ચોળિયો માર્ગ અને શક્તિ પંથ વગેરે પંથો વ્યભિચારની પ્રવૃતિમાં જ મોક્ષ માનતા હતા અને મનાવતા પણ હતા. ગુજરાતમાં મુખ્યત્વે શૈવ, વૈષ્ણવ, જૈન અને શાક્ત એ સંપ્રદાયો જોરમાં પ્રચલિત હતા. તેમાંપણ શાક્ત મત વધારે પ્રસરતો હતો. આ અરસામાં મહેમદાવાદમાં એક બ્રાહ્મણના ઘરમાંથી મહાજને ૬૦ મણ માંસ કઢાવ્યું હતું. તે સમયનું વર્ણન નિષ્કુળાનંદ સ્વામી લખે છે કે-</p><h3 style='text-align: center;'>(ચોપાઇ)</h3><p style='text-align: justify;'> અસત્ય ગુરુએ અવળું બતાવી, દીધો અધર્મ ધર્મ ઠરાવી ।<br /> રાજા ઉન્મત થઇ અપાર, કર્યો સત્ય ધર્મનો સંહાર ।।<br /> આપે પાપ કરે અણલેખે, તેમ પ્રજા કરે દેખા દેખે ।<br /> નરનારી નિયમમાં નથી, કહીએ તેની ભૂંડાઇ શું કથી ।।<br /> ત્યાગી ગૃહી તજી નિજધર્મ, વિષય સારુ કરે છે વિકર્મ ।<br /> નરનારી અપાર છે કામી, કરે ગોત્રમાં ગમન હરામી ।।</p><p style='text-align: right;'>(ભ.-ચિ.-પ્ર-૬-૭)</p><p style='text-align: justify;'> હે ભક્તો ! આવા રાજકીય અને ધાર્મિક અંધાધૂંધીના સમયમાં ગુજરાત અને સૌરાષ્ટ્રનું નવનિર્માણ કરવાનું કામ કેટલું દુષ્કર હતું તેનો સહેજે ખ્યાલ આવી જાય છે. તો આવા ઘોર કળિયુગમાં સ્વયં પૂર્ણ પુરુષોત્તમ શ્રી સ્વામિનારાયણ ભગવાન આ પૃથ્વી ઉપર ઉત્તર પ્રદેશમાં ગોંડા જીલ્લાના છપૈયા ગામમાં પ્રગટ થઇને ૧૧, વર્ષ ૩ માસ અને ૧ દિવસની ઉંમરે ઘરનો ત્યાગ કરી, ૭ વર્ષ ૧ માસ અને ૧૧ દિવસ વન વિચરણ કરી ગુજરાત અને સૌરાષ્ટ્રમાં પધારી સદ્ધર્મનું સ્થાપન કરી મુમુક્ષુઓને યમપુરીના માર્ગે જતા બચાવી લીધા હતા. તેથી તો ત્રિભુવનભાઇ વ્યાસે લખ્યું છે કે-</p><h3 style='text-align: center;'>(છંદ)</h3><p>“ઘોર કલિકાલના દોર છૂટ્યા અને દુષ્ટતાનું બધે જોર વ્યાપ્યું,<br />ભક્તિ સદ્ધર્મના માર્ગ રુંધી દિધા, કર્મ નિષ્કામનું મૂળ કાપ્યું ।,<br />વેદ સત્શાસ્ત્રના અર્થ અવળા કર્યા, પંડિતોએ પાપમાર્ગે જઇને,<br />ધન્ય હો ધર્મધ્વજ રોપિયો એ સમે, સ્વામિનારાયણે પ્રગટ થઇને. ।।”૧<br />“મંત્ર મૂઠ ચોટને કામણો ટુમણો, દેવ દૂગરા ભૂવાને ભરાડી,<br />ભૂતને પલિત જીન ડાકિણી શાકિણી, પીડતા તા પ્રજાને અનાડી ।<br />ઠગ ધુતારા અને જાદુ કીમયા ગરા, ડારતા લોકને પેંધી જઇને,<br />ધન્ય હો ધર્મધ્વજ રોપિયો એ સમે, સ્વામિનારાયણે પ્રગટ થઇને.।।” ૨</p>",
"type": "content",
"child": null
}]
},
{
"title": "૦૩. લીલા શુંકામ કહેવાય ?",
"type": "title",
"child": [{
"title": "<p style='text-align: justify;'> હે ભક્તો ! પરમાત્માએ પ્રગટ થઇ બાળલીલા કરી, વનમાં વિચરણ કર્યું, સૌરાષ્ટ્રમાં પધાર્યા અને ત્યાંથી અનેક ગામડાઓમાં પધારી જે જે લીલાઓ કરી તે તે લીલાઓના મુખ્ય મુખ્ય પ્રસંગો શતાનંદસ્વામીએ લખ્યા તે ગ્રંથનું નામ છે 'સત્સંગિ જીવન. તો તે ગ્રંથના કઠિન શબ્દો સરળ ભાષામાં તેના સાર રૂપે પ્રસંગોપાત્ અનેક દ્રષ્ટાંતો સહિત આપણે સાંભળીએ અને જીવનમાં ઉતારીએ.</p><p style='text-align: justify;'> ભગવાન પૃથ્વી ઉપર પધારી જે જે ક્રિયાઓ કરે છે તેને લીલા કહેવાય છે અને મનુષ્ય જે જે ક્રિયાઓ કરે છે તે તે ક્રિયાઓને કર્મ કહેવાય છે. કારણકે - ભગવાન જે જે ક્રિયાઓ કરે છે તે તે ક્રિયાઓ પોતાની ઇંદ્રિયોને લાડ લડાવવા માટે નથી કરતા, જ્યારે મનુષ્ય જે જે ક્રિયાઓ કરે છે તે તે ક્રિયાઓ ઇંદ્રિયોની ઇચ્છા પૂર્ણ કરવા માટે કરે છે. ભગવાન ક્રિયાઓ કરે છે તેતો ભક્તોની ઇચ્છાઓ પૂર્ણ કરવા માટે કરે છે. ભગવાન જે જે ક્રિયાઓ કરે છે તે તેનું કર્મફળ તેઓને ભોગવવું પડતું નથી, પરંતુ મનુષ્ય ક્રિયાઓ કરે છે તેનું કર્મફળ તેને અવશ્ય ભોગવવું પડે છે. તથા ભગવાન જે જે ક્રિયાઓ કરે છે તેની પાછળ નિસ્વાર્થ હોય છે, જ્યારે મનુષ્ય જે જે ક્રિયાઓ કરે છે તેની પાછળ સ્વાર્થ હોય છે. અને ભગવાન પ્રગટ થાય છે તેની પાછળ અનેક રહસ્યો છુપાયેલા હોય છે, જ્યારે મનુષ્ય જન્મે છે તેતો પોતાના પ્રારબ્ધ કર્મને ભોગવવા માટેજ જન્મે છે. તો આ રીતે પરમાત્માની ક્રિયાનું અને જીવાત્માની ક્રિયાનું કારણ જુદું હોય છે, તે માટે જ પરમાત્મા જે કરે તેને લીલા કહેવાય છે.</p>",
"type": "content",
"child": null
}]
},
{
"title": "૦૪. પરમાત્માને પ્રગટ થવાના હેતુઓ",
"type": "title",
"child": [{
"title": "<p style='text-align: justify;'> હે ભક્તો ! આપણે હવે જોઇએ, ચોવિશ અવતારોને પ્રગટ થવાના હેતુઓ -<br /><strong>(૧)</strong> સનકાદિક :- નૈષ્ઠિક ઉર્ધ્વરેતા બ્રહ્મચર્યનું સ્થાપન કરવા.<br /><strong>(૨)</strong> વરાહ :- હિરણ્યાક્ષ દૈત્ય પૃથ્વીને પાતાળમાં લઇ ગયો હતો, તેથી તે દૈત્યને મારવા અને પૃથ્વીને પાતાળમાંથી ઉપર લાવવા.<br /><strong>(૩)</strong> યજ્ઞ :- સંસારના જીવોને યજ્ઞકર્મ શીખવવા માટે.<br /><strong>(૪)</strong> હયગ્રીવ :- વેદનું રક્ષણ કરવા (તેઓના નાકમાંથી વેદવાણી ઉત્પન્ન થઇ હતી. ભા.-દ્વિ.-અ.-૭મો.) તથા મધુ અને કૈટભ નામના અસુરો થકી બ્રહ્માજીની રક્ષા કરવા.<br /><strong>(૫)</strong> નર-નારાયણ :- ભારતમાં રહેલા મુમુક્ષુ જીવોના કલ્યાણ માટે તપ કરવા તથા સહસ્ત્રકુંચી નામના દૈત્યને મારવા.<br /><strong>(૬)</strong> નૃસિંહ :- હિરણ્યકશિપુને મારવા તથા પ્રહલાદજીની રક્ષા કરવા.<br /><strong>(૭)</strong> કપિલ :- કર્દમઋષિ અને દેવહૂતિની ઇચ્છા પૂર્ણ કરવા અને સાંખ્ય શાસ્ત્રનું જ્ઞાન દેવા.<br /><strong>(૮)</strong> દત્તાત્રેય :- અત્રિઋષિ અને અનસૂયાને પુત્રનું સુખ દેવા તથા ત્યાગ અને યોગ દેખાડવાને અર્થે લક્ષ લઇ ચોવિશ ગુરુકરી બોધદેવા.<br /><strong>(૯)</strong> ઋષભદેવ :- ત્યાગીઓને શિખામણ દેવા કે 'જગતથી નિસ્પૃહ રહો'.<br /><strong>(૧૦)</strong> પૃથુ :- પ્રજાઓનું રક્ષણ કરવા તથા રસરહિત પૃથ્વીને રસાળ કરવા.<br /><strong>(૧૧)</strong> મચ્છ :- સત્યવ્રત રાજાનું રક્ષણ કરવા અને શંખાસુર દૈત્યને મારી બ્રહ્માજીને વેદ પાછા લાવી દેવા.<br /><strong>(૧૨)</strong> કચ્છ :- સમુદ્રમંથન વખતે મંદ્રાચળ પર્વતને પીઠ ઉપર રાખવા.<br /><strong>(૧૩)</strong> ધન્વંતરી :- અમૃતનો ઘડો સમુદ્રમાંથી લઇ દેવતાઓને આપવા તથા ઔષધિઓના નામ,ગુણ અને ઉપયોગ બતાવવા.<br /><strong>(૧૪)</strong> હરિ :- મગરમચ્છ થકી હાથીનું રક્ષણ કરવા.<br /><strong>(૧૫)</strong> નારદ :- નારદ પંચરાત્રનું જ્ઞાન આપવા અને ભક્તિનો પ્રચાર કરવા.<br /><strong>(૧૬)</strong> વામન :- ઇન્દ્રને ત્રિલોકીનું રાજ્ય પાછું અપાવવા.<br /><strong>(૧૭)</strong> હંસ :- સનકાદિકોને તથા નારદજીને જ્ઞાન આપવા.<br /><strong>(૧૮)</strong> નારાયણ :- ધ્રુવજીને દર્શન દેવા.<br /><strong>(૧૯)</strong> પરશુરામ :- આસુરી વૃતિવાળા ક્ષત્રિઓને મારવા.<br /><strong>(૨૦)</strong> રામ :- રાવણ આદિક રાક્ષસોને મારવા અને બીજાં ઘણાં કારણે.<br /><strong>(૨૧)</strong> વ્યાસ :- લોકો સરળતાથી સમજી શકે તે માટે વેદના વિભાગો કરવા તથા પુરાણોની રચના કરવા.<br /><strong>(૨૨)</strong> શ્રીકૃષ્ણ :- કંસાદિક દુષ્ટોને મારવા અને પ્રેમીઓની ઇચ્છા પૂર્ણ કરવા.<br /><strong>(૨૩)</strong> બુદ્ધ :- અસુરોને મોહ ઉપજાવી અહિંસા ધર્મનું સ્થાપન કરવા.<br /><strong>(૨૪)</strong> કલ્કિ :- અધર્મનો નાશ કરી સત્યુગના ધર્મો સ્થાપવા (થશે.)<br /> હે ભક્તો ! આ રીતે દરેક મન્વંતરોમાં પરમાત્મા અવતાર લે છે, પરંતુ તેની પાછળ કંઇક કારણ છુપાયેલું હોય છે. તે માટે જ પ્રભુની તમામ ક્રિયાને લીલા કહેવામા આવે છે.તો પરમાત્માની ક્રિયાને લીલા શું કામ કહેવાય, તેનો તમોને ખ્યાલ આવી ગયો હશે.</p><p style='text-align: center;'><strong>(રાગઃ પૂર્વછાયો)</strong></p><p style='text-align: justify;'>હરિ કથા હવે આદરુ, સદમતિ શ્રોતા જે સાંભળે ।<br />સુણતા તે સુખ ઉપજે, વળી તાપ તનના તે ટળે ।।<br />સર્વે સંત સુજાણને, હું પ્રથમ લાગી પાય ।<br />આદરુ આ ગ્રંથને, જેમા વિઘન કોઇ ન થાય ।।<br />સારી કથા સુંદર અતિ, હું કહું કરી વિસ્તાર ।<br />જે જન મન દઇ સાંભળે, તે ઉતરે ભવજળપાર ।।<br />પ્રગટ પુરુષોતમના, ચરિત્ર પવિત્ર કહું અતિ ।<br />શ્રવણ દઇ જે સાંભળે, થાય તેની નિર્મળ મતિ ।।<br />એવી કથા આદરતા, અતિ ઉમંગ છે મારે અંગે ।<br />અંગમા આનંદ ઉલટ્યો, જાણું કયારે કહું ઉછરંગે ।।<br />અતિ હર્ષછે અંતરે, વળી આનંદ આવ્યો છે અંગમાં ।<br />સુંદર ચરિત્ર શ્રીહરિતણા, કહું હવે હું ઉમંગમાં ।।</p><p style='text-align: right;'>(ભક્તચિંતામણિ)</p>",
"type": "content",
"child": null
}]
}
]
}]
}]
}]
The following is the BookModel that is used.
import Foundation
import SwiftUI
enum BookParseError: Error {
case bookParsingFailed
}
struct BookModelForJSONConversion: Codable {
var id:Int
var title: String?
var content: [BookContent]?
func convertToJsonString()->String?{
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .prettyPrinted
var encodedString:String?
do {
let encodePerson = try jsonEncoder.encode(self)
let endcodeStringPerson = String(data: encodePerson, encoding: .utf8)!
//print(endcodeStringPerson)
encodedString = endcodeStringPerson
} catch {
print(error.localizedDescription)
return nil
}
return encodedString
}
}
struct BookModel: Identifiable, Codable {
var id:Int
var bukTitle: String?
var isLive: Bool?
var userCanCopy: Bool?
var bookContent: [BookContent]?
enum CodingKeys: String, CodingKey {
case id = "id"
case bukTitle = "title"
case isLive = "is_live"
case userCanCopy = "user_can_copy"
case bookContent = "content"
}
}
struct BookContent: Identifiable, Codable {
let id = UUID()
var title, type: String
var child: [Child]
}
struct Child: Identifiable, Codable {
let id = UUID()
var title, type: String
var child: [Child]?
}
@available(iOS 15, *)
func attributedString(from str: String, font: Font) -> AttributedString {
if let theData = str.data(using: .utf16) {
do {
let theString = try NSAttributedString(data: theData, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil)
var attaString = AttributedString(theString)
attaString.font = font // <-- here
return attaString
} catch {
print("\(error)")
}
}
return AttributedString(str)
}
enum BooksDirectory {
/// Default, system Documents directory, for persisting media files for upload.
case downloads
/// Returns the directory URL for the directory type.
///
fileprivate var url: URL {
let fileManager = FileManager.default
// Get a parent directory, based on the type.
let parentDirectory: URL
switch self {
case .downloads:
parentDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
}
return parentDirectory.appendingPathComponent(VBBooksManager.booksDirectoryName, isDirectory: true)
}
}
class VBBooksManager:NSObject {
fileprivate static let booksDirectoryName = "books"
let directory: BooksDirectory
@objc (defaultManager)
static let `default`: VBBooksManager = {
return VBBooksManager()
}()
// MARK: - Init
/// Init with default directory of .uploads.
///
/// - Note: This is particularly because the original Media directory was in the NSFileManager's documents directory.
/// We shouldn't change this default directory lightly as older versions of the app may rely on Media files being in
/// the documents directory for upload.
///
init(directory: BooksDirectory = .downloads) {
self.directory = directory
}
// MARK: - Instance methods
/// Returns filesystem URL for the local Media directory.
///
@objc func directoryURL() throws -> URL {
let fileManager = FileManager.default
let mediaDirectory = directory.url
// Check whether or not the file path exists for the Media directory.
// If the filepath does not exist, or if the filepath does exist but it is not a directory, try creating the directory.
// Note: This way, if unexpectedly a file exists but it is not a dir, an error will throw when trying to create the dir.
var isDirectory: ObjCBool = false
if fileManager.fileExists(atPath: mediaDirectory.path, isDirectory: &isDirectory) == false || isDirectory.boolValue == false {
try fileManager.createDirectory(at: mediaDirectory, withIntermediateDirectories: true, attributes: nil)
}
return mediaDirectory
}
func saveBook(bookName:String,bookData:String)->Error?{
//TODO: Save book into Document directory
do {
var finalBookName = bookName
if !finalBookName.contains(".json"){
finalBookName = "\(bookName).json"
}
let bookPath = try? self.directoryURL().appendingPathComponent(finalBookName)
print(bookPath?.relativePath)
do {
let fileManager = FileManager.default
if fileManager.fileExists(atPath: bookPath!.relativePath){
try fileManager.removeItem(at: bookPath!)
}
let data = Data(bookData.utf8)
try? data.write(to: bookPath!, options: .atomic)
//Just for Testing purpose call load book
//lodBook(bookName: finalBookName)
}
catch let error as NSError {
print(error)
return error
}
}
catch let error as NSError{
print(error)
return error
}
return nil
//fileManager.wri wr(bookPath.relativePath, contents: Data(bookData), attributes: nil)
}
//https://stackoverflow.com/questions/39415249/best-practice-for-swift-methods-that-can-return-or-error
func loadBookFromDocumentDirectory(bookName:String) throws -> BookModel? {
let fileManager = FileManager.default
do {
var finalBookName = bookName
if !finalBookName.contains(".json"){
finalBookName = "\(bookName).json"
}
let bookPath = try? self.directoryURL().appendingPathComponent(finalBookName)
print(bookPath?.relativePath)
do {
if fileManager.fileExists(atPath: bookPath!.relativePath){
let jsonBookString = fileManager.contents(atPath: bookPath!.relativePath)
do {
let data = try Data(jsonBookString!)
guard let parsedBookObject:BookModel? = try JSONDecoder().decode(BookModel.self, from: data) else {
throw BookParseError.bookParsingFailed
}
return parsedBookObject ?? nil
//print(parsedBookObject)
}
catch let error as NSError{
print("error: \(error)")
throw error
}
}else{
}
}
catch let error as NSError {
print(error)
throw error
}
}
catch let error as NSError{
print(error)
throw error
}
return nil
}
func loadAllSavedBooks()->[BookModel]?{
var allBooks:[BookModel] = []
let fileManager = FileManager.default
guard let booksPath = try? self.directoryURL() else {
return []
}
print(booksPath)
do {
// Get the directory contents urls (including subfolders urls)
let directoryContents = try fileManager.contentsOfDirectory(at: booksPath, includingPropertiesForKeys: nil)
print(directoryContents)
// if you want to filter the directory contents you can do like this:
let books = directoryContents.filter{ $0.pathExtension == "json" }
let bookNames = books.map{ $0.deletingPathExtension().lastPathComponent }
print("bookNames list:", bookNames)
//TODO: Load all the books and send array back
for bookName in bookNames {
do {
let book = try loadBookFromDocumentDirectory(bookName:bookName)
allBooks.append(book!)
} catch BookParseError.bookParsingFailed {
continue
}
}
return allBooks
} catch let error as NSError {
print(error)
}
return allBooks
}
}
and loading the books
import Foundation
class BooksList: ObservableObject {
@Published var books:[BookModel]
init() {
let booksManager = VBBooksManager()
books = booksManager.loadAllSavedBooks() ?? []
}
}
Attributed string Function as follows
@available(iOS 15, *)
func attributedString(from str: String, font: Font) -> AttributedString {
if let theData = str.data(using: .utf16) {
do {
let theString = try NSAttributedString(data: theData, options: [.documentType: NSAttributedString.DocumentType.html], documentAttributes: nil)
var attaString = AttributedString(theString)
attaString.font = font // <-- here
return attaString
} catch {
print("\(error)")
}
}
return AttributedString(str)
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|

