Tutorial details

Tutorial 17 - A Simple File Manager for Codea | App Code for Sale | Preview

Tutorial 17 - A Simple File Manager for Codea | iOS Tutorial

How to store data

Overview PAGE TOP

Tutorial 16 explained the various ways that data can be stored using Codea. In order to facilitate the loading and storing of data for our level generator we created a simple file management class.

This version handles Local Data, Project Data, Project Information and Global Data. Remember that all of this data is stored in string format using a pList which is accessed by a unique string called the key.

The File Manager is constructed using two ListScroll objects (a class written by sanit over on the Codea Forum), a text box showing the value of the selected key and a MenuBar object (a class written by dave1707 also from the Codea Forum).

The Main class is used to load some test data into the four data stores and then instantiate the FileManager class. We have provided stubs for the functions called when the MenuBar items are tapped. The only menu item which has been implemented is delete file. WARNING - file deletion can NOT be undone and there is no confirmation required to delete a file so back up your data and use this class with care (or delete this functionality). Feel free to delete the test data which is loaded in setup(), this will be recreated every time you run the App.

The data you need to take particular care with is Global Data as this may have been stored by another Codea App. For example, if you have used Spritely (the sprite creation example program which comes with Codea) then any sprites that you have created will be stored in global data.

The delete function has not been implemented for Project Info because there is no way to determine what keys are in there (i.e. there is no listProjectInfo function).

To delete a file we just assign the value of the selected key to nil. We will provide examples of the load and save function when we incorporate FileManager into our Tower Defence Level Generator (dGenerator).

The line FileManager:init() will setup your FileManager class and prefetch the keys for each persistent data store.

The class handles both portrait and landscape orientation. The orientationChanged() function adjusts the FileManager position when the iPad is rotated. It works but not very well as ListScroll wasn't designed to handle this. You may have to drag the ListScroll box to show the contents. We haven't had a chance to modify this.

1   -- FileManager
2   --
3   -- Codea FileManager v1.1
4   --
5   -- A simple file manager to examine the Codea provided
6   -- persistent storage. Currently handles Local Data, Project Data,
7   -- Project Information and Global Data.
8   --
9   -- This App demonstrates how to use this class in your project.
10  --
11  -- Reefwing Software
12  -- 15 September 2012
13  --
14  -- WARNING - FILE DELETION CAN NOT BE UNDONE AND DOES NOT ASK FOR CONFIRMATION.
15  --           USE WITH EXTREME CAUTION AND BACK UP YOUR DATA BEFORE USING THIS
16  --           FILE MANAGER CLASS.
17  
18  supportedOrientations(ANY)
19  displayMode(FULLSCREEN)
20  
21  -- Use this function to perform your initial setup
22  
23  function setup()
24      
25      -- Load test data to illustrate the FileManager class
26      -- First save some ProjectInfo data. This is specific to the App.
27      
28      saveProjectInfo("Description", "File Manager for Codea v"..version)
29      saveProjectInfo("Author", "Reefwing Software")
30      saveProjectInfo("Date", "15 September, 2012")
31      saveProjectInfo("Version", version)
32      saveProjectInfo("Comments", "Original Release.")
33      
34      print("-- Codea File Manager v"..version.."\n")
35      
36      -- Save local data, this is accessible from within this App on your device.
37      
38      saveLocalData("localDataKey", "Some local data. For example a high score.")
39      
40      -- Save project data, this is accessible from within this App but isn't device specific.
41      
42      saveProjectData("projectDataKey", "Some project data. For example level or map info.")
43      
44      -- Save global data, this is accessible from any Codea App on this device.
45      
46      saveGlobalData("globalDataKey", "Some global data. For example images from spritely or data from a level generator like dGenerator.")
47      
48      -- Initialise the FileManager class
49      
50      FileManager:init()
51      
52  end
53  
54  -- Menu Bar Call Back Methods
55  
56  function cancelFileManager()
57      -- Custom implementation goes here
58  end
59  
60  function aboutFileManager()
61      -- Custom implementation goes here
62  end
63  
64  function saveFile()
65      -- Custom implementation goes here
66  end
67  
68  function loadFile()
69      -- Custom implementation goes here
70  end
71  
72  function deleteFile()
73      if currentDirectory == nil then
74          -- No Directory Selected
75      elseif currentDirectory == ProjectData and projectKeyTable[currentKey] ~= nil then
76          saveProjectData(projectKeyTable[currentKey], nil)
77          loadProjectKeys()
78          displayKeys(projectKeyTable)
79          currentKey = 1
80          valueString = string.truncate(readProjectData(projectKeyTable[currentKey]) or "nil",150)
81      elseif currentDirectory == ProjectInfo and infoKeyTable[currentKey] ~= nil then
82          -- delete is not currently supported for ProjectInfo because we can't
83          -- get a list of the keys in this pList.
84      elseif currentDirectory == LocalData and localKeyTable[currentKey] ~= nil then
85          saveLocalData(localKeyTable[currentKey], nil)
86          loadLocalKeys()
87          displayKeys(localKeyTable)
88          currentKey = 1
89          valueString = string.truncate(readLocalData(localKeyTable[currentKey]) or "nil",150)
90      elseif currentDirectory == GlobalData and globalKeyTable[currentKey] ~= nil then
91          saveGlobalData(globalKeyTable[currentKey], nil)
92          loadGlobalKeys()
93          displayKeys(globalKeyTable)
94          currentKey = 1
95          valueString = string.truncate(readGlobalData(globalKeyTable[currentKey]) or "nil",150)
96      end
97  end
98  
99  -- View Handling
100 
101 function orientationChanged(newOrientation)
102     
103     -- Update ListScroll co-ordinates for new orientation
104     
105     local y = HEIGHT - 500 
106     
107     if directoryList ~= nil then
108         directoryList.pos.y = y
109     end
110     
111     if dataKeyList ~= nil then
112         dataKeyList.pos.y = y
113     end
114     
115     -- Update Menu Bar co-ordinates for new orientation
116     
117     y = HEIGHT - 80
118     
119     if b1tab ~= nil then
120         for i = 1, #b1tab do
121             b1tab[i].y = y
122         end
123     end
124      
125     y = HEIGHT - 110
126    
127     if b2tab ~= nil then
128         for i = 1, #b2tab do
129             b2tab[i].y = y
130             y = y - 30
131         end
132     end
133     
134 end
135 
136 function draw()
137     
138     -- This sets a black background color
139     
140     background(0)
141     
142     -- Draw the FileManager
143     
144     FileManager:draw()
145     
146 end
147 
148 -- Touch Handler
149 
150 function touched(touch)
151         
152     -- Handle FileManager touches
153     
154     FileManager:touched(touch)
155 
156 end

17.2 The FileManager Class PAGE TOP

Most of the hard work is done in this class. We start off by defining variables to represent the four supported Directory Types to make the code easier to read. The init() function creates the two ListScrolls (one for the list of Directories called directoryList and one for the keys it contains called dataKeyList).

We then pre-load the keys for Project Data, Local Data and Global Data (we already know the Project Info keys since we loaded them). We set the current directory to Project Info and set the current key to the first one. There is a variable called valueString which we use to contain the value of the selected string. Only the first 150 characters of the saved value are displayed. The last thing we do in init() is setup the MenuBar.

One of the modifications we had to make to the MenuBar class was to prevent touches on the ListScroll when a sub menu is displayed (otherwise you could accidentally delete the wrong file).

1   -- Define Directory Types
2   
3   ProjectInfo = 1
4   ProjectData = 2
5   LocalData = 3
6   GlobalData = 4
7   
8   -- Class version
9   
10  version = 1.1
11  
12  -- Codea FileManager v1.1
13  --
14  -- A simple file manager to examine the Codea provided
15  -- persistent storage. Currently handles Local Data, Project Data,
16  -- Project Information and Global Data.
17  --
18  -- Reefwing Software
19  -- 15 September 2012
20  --
21  -- This class requires the ListScroll and TextItem class written by @sanit and
22  -- the MenuBar class written by @dave1707 (with some modifications).
23  --
24  -- WARNING - FILE DELETION CAN NOT BE UNDONE AND THE CLASS DOES NOT ASK FOR CONFIRMATION.
25  --           USE WITH EXTREME CAUTION AND BACK UP YOUR DATA BEFORE USING THIS
26  --           FILE MANAGER CLASS.
27  
28  FileManager = class()
29  
30  function FileManager:init()
31      
32      -- Initialise the FileManager parameters and
33      -- load up the currently supported data stores.
34      
35      directoryList = ListScroll(vec2(25, HEIGHT - 500), 200, 400)
36      directoryContents = {"Project Info", "Project Data", "Local Data", "Global Data"}
37      
38      for i = 1, #directoryContents do
39          local item = TextItem(i, directoryContents[i])
40          if i == 1 then
41              -- pre select Project Info "Directory"
42             item.selected = true
43          end
44          directoryList:add(item)
45      end
46      
47      currentDirectory = ProjectInfo
48      
49      dataKeyList = ListScroll(vec2(227, HEIGHT - 500), 260, 400)
50      
51      -- Pre-fetch results
52      
53      infoKeyTable = {"Description", "Author", "Date", "Version", "Comments"}
54  
55      loadProjectKeys()
56      loadLocalKeys()
57      loadGlobalKeys()
58      displayKeys(infoKeyTable)
59      
60      currentKey = 1
61      valueString = readProjectInfo(infoKeyTable[currentKey])
62      
63      -- Setup the MenuBar
64      
65      MenuSetup()
66      
67  end
68  
69  -- Functions to read keys from the available pLists
70  
71  function loadProjectKeys()    
72      projectKeyTable = listProjectData()
73      if #projectKeyTable == 0 then
74          projectKeyTable = {"nil"}
75      end
76  end
77  
78  function loadLocalKeys()
79      localKeyTable = listLocalData()
80      if #localKeyTable == 0 then
81          localKeyTable = {"nil"}
82      end
83  end
84  
85  function loadGlobalKeys()
86      globalKeyTable = listGlobalData()
87      if #globalKeyTable == 0 then
88          globalKeyTable = {"nil"}
89      end 
90  end
91  
92  -- This function displays the keys passed in keyTable within the dataKeyList ListScroll
93  
94  function displayKeys(keyTable)
95      
96      dataKeyList.items = {}
97      for i = 1, #keyTable do
98          local item = TextItem(i, keyTable[i])
99          if i == 1 then
100             -- pre select first key in Project Info
101            item.selected = true
102         end
103         dataKeyList:add(item)
104     end
105     
106 end
107 
108 -- Setup the menu items at the top of the ListScrolls
109 -- Note that the call back functions are in the Main tab.
110 
111 function MenuSetup()
112     
113     pointer2 = nil
114     pointer3 = nil
115     
116     b1tab = {}
117     b2tab = {}
118     
119     local y = HEIGHT - 80
120     
121     -- Create tables for main menu bar
122     
123     table.insert(b1tab, MenuBar(80, y, 100, 30, "File", b2tab))
124     table.insert(b1tab, MenuBar(180, y, 100, 30, "Cancel", cancelFileManager))
125     table.insert(b1tab, MenuBar(280, y, 100, 30, "About", aboutFileManager))
126     
127     pointer1 = b1tab
128     
129     y = HEIGHT - 110
130     
131     -- Create table for sub menu items
132     
133     table.insert(b2tab, MenuBar(80, y, 100, 30, "Save", saveFile))
134     table.insert(b2tab, MenuBar(80, y - 30, 100, 30, "Load", loadFile))
135     table.insert(b2tab, MenuBar(80, y - 60, 100, 30, "Delete", deleteFile))
136     
137     -- Global variables to prevent touches on scroll list
138     -- while subMenu is visible and to update the key list
139     -- if the directory changes.
140     
141     subMenuShown = false
142     directoryChanged = false
143     
144 end
145 
146 -- Update functions for List Scrolls
147 
148 function updateDirectorySelection()
149 
150     local dlsi = directoryList.selectedItem
151     
152     if dlsi ~= currentDirectory then
153         if dlsi == nil then
154             -- No Items Selected assign to default
155             dlsi = ProjectInfo
156             displayKeys(infoKeyTable)
157         elseif dlsi == ProjectData then
158             displayKeys(projectKeyTable)
159         elseif dlsi == ProjectInfo then
160             displayKeys(infoKeyTable)
161         elseif dlsi == LocalData then
162             displayKeys(localKeyTable)
163         elseif dlsi == GlobalData then
164             displayKeys(globalKeyTable)
165         end
166         currentDirectory = dlsi
167         directoryChanged = true
168     end
169     
170 end
171 
172 function updateKeySelection()
173     
174     local dksi = dataKeyList.selectedItem
175     
176     if dksi ~= currentKey or directoryChanged then
177         if directoryChanged then
178             dataKeyList.selectedItem = 1
179             currentKey = 1
180             directoryChanged = false
181         else
182             currentKey = dksi
183         end
184         
185         if currentDirectory == nil then
186             -- No Directory Selected
187             valueString = ""
188         elseif currentDirectory == ProjectData and projectKeyTable[currentKey] ~= nil then
189             valueString = readProjectData(projectKeyTable[currentKey]) or "nil"
190         elseif currentDirectory == ProjectInfo and infoKeyTable[currentKey] ~= nil then
191             valueString = readProjectInfo(infoKeyTable[currentKey]) or "nil"
192         elseif currentDirectory == LocalData and localKeyTable[currentKey] ~= nil then
193             valueString = readLocalData(localKeyTable[currentKey]) or "nil"
194         elseif currentDirectory == GlobalData and globalKeyTable[currentKey] ~= nil then
195             valueString = readGlobalData(globalKeyTable[currentKey]) or "nil"
196         end
197 
198         valueString = string.truncate(valueString, 150)
199     end
200     
201 end
202 
203 function FileManager:draw()
204     
205     -- Codea does not automatically call this method
206     -- Handle Directory Selection
207     
208     updateDirectorySelection()
209     updateKeySelection()
210     directoryList:draw()
211     dataKeyList:draw()
212     
213     -- Draw Menu Bar
214     
215     pushStyle()
216     fill(0,0,255,255)
217     rect(25, HEIGHT - 98, 725, 36)
218     popStyle()
219     
220     MenuBar:menu1()
221     
222     -- Draw the results window
223     
224     pushStyle()
225     textWrapWidth(250)
226     textMode(CORNER)
227     font("Courier")
228     fontSize(24)
229     fill(255)
230     rect(489, HEIGHT - 500, 260, 400)
231     fill(0)
232     local _,h = textSize(valueString)
233     text(valueString, 496, HEIGHT - 100 - h)
234     popStyle()
235     
236 end
237 
238 function FileManager:touched(touch)
239     
240     -- Codea does not automatically call this method
241     
242     if touch.state == BEGAN then
243         MenuBar:check(touch)
244     end 
245     
246     if pointer2 ~= nil then
247         -- Sub menu visible
248         subMenuShown = true    
249     elseif subMenuShown and touch.state == ENDED then
250         subMenuShown = false
251     else 
252         -- Sub menu is not visible so handle scroll touches
253         directoryList:touched(touch)
254         dataKeyList:touched(touch)
255     end     
256     
257 end
258 
259 -- String Helper
260 
261 function string.truncate(str, num)
262     if string.len(str) > num then
263         str = string.sub(str,1,150) .. "..."    
264     end
265     return str
266 end

17.3 Download the Code PAGE TOP

You can download all of the code for this program using the following links:

  1. FileManager Complete Code v1.1 - All of the code in one file.
  2. Main.lua - The Main tab class only.
  3. FileManager.lua - The FileManager v1.1 class only.
  4. ListScroll.lua - The ListScroll class from sanit.
  5. TextItem.lua - The TextItem class used in ListScroll from sanit.
  6. MenuBar.lua - The MenuBar class v1.1 from dave1707 (modified) .

Next up we will incorporate FileManager into our Tower Defence Level Generator.

Reference PAGE TOP

http://codeatuts.blogspot.in/2012/09/tutorial-17-simple-file-manager-for.html

0 Comments Leave a comment

Please login in order to leave a comment.

Newest first
!

Sign-in to your Chupamobile Account.

The Easiest way to Launch your next App or Game.

Join Chupamobile and get instant access to thousands of ready made App and Game Templates.

Creating an account means you’re okay with Chupamobile’s Terms of Service and Privacy Policy.