| Application Name | Christian Prayer Minder |
| Version | 1.0.7.3 (attention: prayer files from versions prior to 1.0.0.9 aren't compatible with later versions of the program; If you currently have v1.0.1.1 or earlier installed, please manually install version 1.0.6.9 after uninstalling any previous version. From now on, you should be able to update from within the program as usual. If you have v1.0.1.2 or later installer, you should be able to download the updated installer from within your currently running program.) |
| Short Description | provides informative texts on prayer-related topics, plus enables easy save/retrieve/edit prayer files, and searching prayer files based on tags and/or author |
| Supported OSes | Windows XP forward |
| Setup File (4.95 M) | http://kyrathaba.dcmembers.com/ccount/click.php?id=8 |
| Memory Footprint | roughly 10 Mb |
| System Requirements | requires .NET Framework v4.0 (program detects if absent, and will download/install it if permission is given) |
| Author Info | DC member kyrathaba, developer of these other NANY 2012 entries: Found Money, Kyrathaba's Hangman, and Source Code Line Counter. My past NANY entries include: Crocus Contacts, Blackjack, and NANY Excuse Manager. Later NANY entries include 2x2 List Sorter (download here), and KyrTTS (Kyrathasoft's Text-to-Sound) (download here). |
| Description | I realize that there are relatively few Christianity adherents here. Nevertheless, for those of us who are, I believe that this program offers something valuable. I began thinking about writing this application several weeks ago, after a series of conversations with my pastor in which we discussed how it's often difficult to concentrate while trying to pray. We've also discussed the need for a tool that acts as a prayer reminder, and one that can track written prayers and offer search functionality. Finally, we wanted a tool that allows the user to come back at a later time to a prayer and offer thoughts/insights into prayer-answers, or meditations on the prayer itself. This tool will also, in future updates, allow the user to customize prompts and prompt-frequencies for various types of prayer (praise, intercession, supplication, etc.) The program could also be used to store diary/journal entries, although that isn't its intended purpose. |
| Screencast | |
| Features | - built-in CHM Help file
- pray at the speed of typing (for me, that's about 85 wpm)
- enter author, and any related tags to help in future searches (or omit them)
- main form features fantastic background images, many of them by J. R. Bell
- twelve fore-/back-color schemes for the "My Prayers" panel
- option to launch application when Windows starts
- ten in-depth articles on prayer-related topics
- articles on spiritual disciplines, and the Biblical plan of salvation
- ability to print the article, or whatever portion of its text is selected
- recommended further reading (some titles with accompanying URLs)
- real-time filesystem watcher monitors for creation/deletion/renaming of prayer files
- informative message-boxes
- program uses index files to make searching for specific prayer files faster
- warns user if they attempt to save a prayer file in a non-MyPrayers directory
- error-trapping correctly detects and handles case where user attempts to load a non-PrayerMinder file
- click a Search result in ListBox to view its filename, lastModified date, path to file, Author, and tags
- double-click the Search result entry to load that prayer file
- zero Registry footprint
- you can now increase or decrease font size in the MyPrayers textbox by selecting your desired font size in Options
- three ways to exit application: close button, file menu, or Escape key
- optional "Did You Know" dialog at program startup
- search either by author and/or tags, using indexes (fast: on the order of milliseconds)
- search within prayer file contents for a search phrase, returning all files that contain that search phrase (slow: seconds, not milliseconds)
- if you double-click a Search results listbox entry and it is the result of a search-within-for-phrase Search, the search-phrase is highlighted when the prayer file is loaded
- smart-saving removes any excess whitespace from the prayer before saving it
- option to set a backup directory (makes program compatible with using Dropbox for backing up the program's data files)
- option to password individual author-name, so that user can't create files with that author name or load files authored by that author without the proper password
|
| Favorite method in this project: bgWorkerSearch_DoWork() | Spoiler (click to show/hide) void bgWorkerSearch_DoWork (object sender, DoWorkEventArgs e) {
log.write("We have entered the background worker that does the heavy-lifting in Searches...");
DateTime _start = DateTime.Now;
clsSearcherArgument arg = (clsSearcherArgument)e.Argument;
#region ifDebuggerAttachedGiveSomeInfo
if (Debugger.IsAttached) {
string msg = "Search type: " + ((SearchType)arg.SearchType).ToString() + Environment.NewLine;
msg += "Search ";
msg += (arg.SearchType == (int)SearchType.SearchWithinFiles) ? " phrase: " : " tag(s): ";
if (arg.searchPhraseOrTags.Length > 0) {
msg += arg.searchPhraseOrTags + Environment.NewLine;
} else {
msg += "[none]" + Environment.NewLine;
}
msg += "Author filter: ";
if (arg.searchedForAuthor.Length > 0) {
msg += arg.searchedForAuthor + Environment.NewLine;
} else {
msg += "[none]" + Environment.NewLine;
}
msg += "Time constraint: " + ((TimeConstraint)arg.timeConstraint).ToString();
MessageBox.Show(msg);
}
#endregion
#region setUpNeededVariables
DirectoryInfo di = new DirectoryInfo(pathToMyPrayers);
FileInfo[] fi = di.GetFiles();
List<clsPrayerInfo> information = new List<clsPrayerInfo>();
int totalPrayerFiles = fi.GetLength(0);
string searchedForAuthor = arg.searchedForAuthor.Trim().ToLower();
string searchedForPhrase = arg.searchPhraseOrTags.Trim().ToLower();
int examined_so_far = 0;
int hits = 0;
int time_constraint = arg.timeConstraint;
double totalSeconds = 0;
bool blnPassesTimeConstraint;
bool blnPassesAuthor;
bool blnPassesSearchPhrase;
decimal fraction = 0;
int the_percent = 0;
for (int i = 0; i < totalPrayerFiles; i++) {
if (fi[i].FullName.ToLower().Contains("thumbs.db")) { totalPrayerFiles--; }
}
#endregion
if (arg.SearchType == (int)SearchType.SearchWithinFiles) {
log.write("About to enter foreach loop for searching within files...");
foreach (FileInfo f in fi) {
blnPassesTimeConstraint = false;
blnPassesAuthor = false;
blnPassesSearchPhrase = false;
if (f.FullName.ToLower().Contains("thumbs.db")) { continue; }
#region codeForExaminingWithinPrayerFileContents
blnPassesAuthor = true; //because SearchWithinFiles doesn't care about the author
FileStream fs = new FileStream(f.FullName, FileMode.Open, FileAccess.Read, FileShare.None);
clsPrayerInfo oInfo = new clsPrayerInfo();
try {
BinaryFormatter bFormatter = new BinaryFormatter();
clsPrayer prayer = (clsPrayer)bFormatter.Deserialize(fs);
string contents = prayer.content.Trim().ToLower();
if (contents.Contains(searchedForPhrase)) {
blnPassesSearchPhrase = true;
oInfo = new clsPrayerInfo(prayer, f.FullName);
int selStart = contents.IndexOf(searchedForPhrase);
oInfo.StartOfSelection = selStart;
#region determineIfWePassTheTimeConstraint
if (time_constraint == (int)TimeConstraint.NoConstraint) {
blnPassesTimeConstraint = true;
} else {
DateTime rightNow = DateTime.Now;
TimeSpan ts = rightNow.Subtract(oInfo.lastModified);
totalSeconds = ts.TotalSeconds;
switch (time_constraint) {
case (int)TimeConstraint.PastWeek:
if (totalSeconds <= 604800) { blnPassesTimeConstraint = true; }
break;
case (int)TimeConstraint.PastMonth:
if (totalSeconds <= 2592000) { blnPassesTimeConstraint = true; }
break;
case (int)TimeConstraint.PastYear:
if (totalSeconds <= 31536000) { blnPassesTimeConstraint = true; }
break;
}
}
#endregion
} else {
blnPassesSearchPhrase = false;
}
examined_so_far++;
log.write("We have examined this many files: " + examined_so_far.ToString());
if (blnPassesTimeConstraint && blnPassesSearchPhrase && blnPassesAuthor) {
information.Add(oInfo);
hits++;
}
} catch (Exception exceptionOpeningPrayerFile) {
string msgWithinFilesException = "Error in SearchWithinFiles portion of code in method bgWorkerSearch_DoWork(): " + exceptionOpeningPrayerFile.Message;
log.write(msgWithinFilesException);
MessageBox.Show(msgWithinFilesException, "Error Opening Prayer File During Search");
}
finally {
if (fs != null) { fs.Close(); }
}
#endregion
fraction = (decimal)examined_so_far / (decimal)totalPrayerFiles;
the_percent = Convert.ToInt32(fraction * 100);
bgWorkerSearch.ReportProgress(the_percent);
log.write("Records counted: " + examined_so_far.ToString() + " of " + totalPrayerFiles.ToString() + " (hits: " + hits.ToString() + ") -- " + the_percent.ToString() + " % complete...");
}
} else {
log.write("About to enter foreach loop for searching via tracking files...");
foreach (FileInfo f in fi) {
blnPassesTimeConstraint = false;
blnPassesAuthor = false;
blnPassesSearchPhrase = false;
if (f.FullName.ToLower().Contains("thumbs.db")) { continue; }
#region codeForSearchingAgainstAuthorAndOrTagsUsingTrackingFiles
clsPrayerInfo oInfo = new clsPrayerInfo();
string pathToTracker = Path.Combine(pathToTrackingDirectory, Path.GetFileNameWithoutExtension(f.FullName));
if (!File.Exists(pathToTracker)) {
log.write("Tracking file doesn't exist: " + pathToTracker);
continue;
} else {
log.write("The following tracking file DOES exist: " + pathToTracker);
}
FileStream fs = new FileStream(pathToTracker, FileMode.Open, FileAccess.Read, FileShare.None);
try {
BinaryFormatter bFormatter = new BinaryFormatter();
oInfo = (clsPrayerInfo)bFormatter.Deserialize(fs);
oInfo.StartOfSelection = -1;
DateTime rightNow = DateTime.Now;
TimeSpan ts = rightNow.Subtract(oInfo.lastModified);
totalSeconds = ts.TotalSeconds;
log.write("We were able to open the tracker...");
#region determineIfTheTimeConstraintPasses
if (time_constraint == (int)TimeConstraint.NoConstraint) {
blnPassesTimeConstraint = true;
} else {
switch (time_constraint) {
case (int)TimeConstraint.PastWeek:
if (totalSeconds <= 604800) { blnPassesTimeConstraint = true; }
break;
case (int)TimeConstraint.PastMonth:
if (totalSeconds <= 2592000) { blnPassesTimeConstraint = true; }
break;
case (int)TimeConstraint.PastYear:
if (totalSeconds <= 31536000) { blnPassesTimeConstraint = true; }
break;
}
}
#endregion
if (blnPassesTimeConstraint) {
log.write("TimeConstraint passed in Search using Mode Normal or ExactMatch...");
#region determineIfAuthorPasses
if (searchedForAuthor.Length == 0) {
blnPassesAuthor = true;
} else {
if (searchedForAuthor == oInfo.author.Trim().ToLower()) { blnPassesAuthor = true; }
}
#endregion
if (blnPassesAuthor) {
#region determineIfSearchPhrasePasses
if (searchedForPhrase.Length == 0) {
blnPassesSearchPhrase = (arg.SearchType == (int)SearchType.Normal) ? true : false;
} else {
if (arg.SearchType == (int)SearchType.ExactMatch) {
blnPassesSearchPhrase = (searchedForPhrase == oInfo.tags.Trim().ToLower()) ? true : false;
} else {
blnPassesSearchPhrase = (oInfo.tags.Trim().ToLower().Contains(searchedForPhrase)) ? true : false;
}
}
#endregion
}//end if (blnPassesAuthor)
}//end if (blnPassesTimeContraint)
if (blnPassesSearchPhrase && blnPassesAuthor && blnPassesTimeConstraint) {
information.Add(oInfo);
hits++;
}
examined_so_far++;
log.write("We have examined this many files: " + examined_so_far.ToString());
} catch (Exception exception) {
log.write("Exception caught while trying to load clsPrayerInfo data from this tracking file in bgWorkerSearch_DoWork(): " + Path.GetFileName(pathToTracker));
log.write(exception.Message);
}
finally {
if (fs != null) { fs.Close(); }
}
#endregion
fraction = (decimal)examined_so_far / (decimal)totalPrayerFiles;
the_percent = Convert.ToInt32(fraction * 100);
bgWorkerSearch.ReportProgress(the_percent);
log.write("Records counted: " + examined_so_far.ToString() + " of " + totalPrayerFiles.ToString() + " (hits: " + hits.ToString() + ") -- " + the_percent.ToString() + " % complete...");
}
}
DateTime _finished = DateTime.Now;
TimeSpan tsOverall = _finished.Subtract(_start);
string duration = clsGetDurationDesc.getDurationDesc(tsOverall.TotalMilliseconds);
clsSearcherResults oResults = new clsSearcherResults(information, duration, examined_so_far, hits);
e.Result = oResults;
log.write("Now exiting bgWorkerSearch_DoWork()...");
}
|
| Screenshots (there are more images in addition to those shown here, but you'll have to download/install the program to discover them...) | |
| Installation | run the Inno Setup installer |
| Using the application | pretty standard Windows application menu system, with some additional options. Should be straightforward, although I intend to author a help file. |
| Uninstalling | Run the uninstaller that the installation provides |
| Known Issues | I've fixed quite a few minor issues. Let me know if you think you've found a bug: it's probably a feature  |