text:
package hu.pe.thinhhoang.aaosync;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.support.v7.app.ActionBar;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.preference.RingtonePreference;
import android.support.v7.app.AlertDialog;
import android.text.TextUtils;
import android.util.Log;
import android.view.MenuItem;

import java.lang.ref.PhantomReference;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import hu.pe.thinhhoang.aaosync.database.exams.ExamsHelper;
import hu.pe.thinhhoang.aaosync.database.grades.GradesHelper;
import hu.pe.thinhhoang.aaosync.database.timetable.SubjectHelper;
import hu.pe.thinhhoang.aaosync.service.SyncHelper;
import hu.pe.thinhhoang.aaosync.service.SyncOrchestrator;
import hu.pe.thinhhoang.aaosync.settings.Settings;
import hu.pe.thinhhoang.aaosync.utils.TimeTeller;
import hu.pe.thinhhoang.aaosync.utils.VoidInterface;

/**
 * A {@link PreferenceActivity} that presents a set of application settings. On
 * handset devices, settings are presented as a single list. On tablets,
 * settings are split by category, with category headers shown to the left of
 * the list of settings.
 *

 * See
 * Android Design: Settings for design guidelines and the Settings
 * API Guide for more information on developing a Settings UI.
 */
public class SettingsActivity extends AppCompatPreferenceActivity {
    /**
     * A preference value change listener that updates the preference's summary
     * to reflect its new value.
     */
    private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object value) {
            String stringValue = value.toString();

            if (preference instanceof ListPreference) {
                // For list preferences, look up the correct display value in
                // the preference's 'entries' list.
                ListPreference listPreference = (ListPreference) preference;
                int index = listPreference.findIndexOfValue(stringValue);

                // Set the summary to reflect the new value.
                preference.setSummary(
                        index >= 0
                                ? listPreference.getEntries()[index]
                                : null);

            } else if (preference instanceof RingtonePreference) {
                // For ringtone preferences, look up the correct display value
                // using RingtoneManager.
                if (TextUtils.isEmpty(stringValue)) {
                    // Empty values correspond to 'silent' (no ringtone).
                    preference.setSummary(R.string.pref_ringtone_silent);

                } else {
                    Ringtone ringtone = RingtoneManager.getRingtone(
                            preference.getContext(), Uri.parse(stringValue));

                    if (ringtone == null) {
                        // Clear the summary if there was a lookup error.
                        preference.setSummary(null);
                    } else {
                        // Set the summary to reflect the new ringtone display
                        // name.
                        String name = ringtone.getTitle(preference.getContext());
                        preference.setSummary(name);
                    }
                }

            } else {
                // For all other preferences, set the summary to the value's
                // simple string representation.
                preference.setSummary(stringValue);
            }
            return true;
        }
    };

    /**
     * Helper method to determine if the device has an extra-large screen. For
     * example, 10" tablets are extra-large.
     */
    private static boolean isXLargeTablet(Context context) {
        return (context.getResources().getConfiguration().screenLayout
                & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
    }

    /**
     * Binds a preference's summary to its value. More specifically, when the
     * preference's value is changed, its summary (line of text below the
     * preference title) is updated to reflect the value. The summary is also
     * immediately updated upon calling this method. The exact display format is
     * dependent on the type of preference.
     *
     * @see #sBindPreferenceSummaryToValueListener
     */
    private static void bindPreferenceSummaryToValue(Preference preference) {
        // Set the listener to watch for value changes.
        preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);

        // Trigger the listener immediately with the preference's
        // current value.
        sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
                PreferenceManager
                        .getDefaultSharedPreferences(preference.getContext())
                        .getString(preference.getKey(), ""));
    }

    private static void setSummaryValue(Preference preference)
    {
        String stringValue = PreferenceManager
                .getDefaultSharedPreferences(preference.getContext())
                .getString(preference.getKey(), "");

        if (preference instanceof ListPreference) {
            // For list preferences, look up the correct display value in
            // the preference's 'entries' list.
            ListPreference listPreference = (ListPreference) preference;
            int index = listPreference.findIndexOfValue(stringValue);

            // Set the summary to reflect the new value.
            preference.setSummary(
                    index >= 0
                            ? listPreference.getEntries()[index]
                            : null);

        } else if (preference instanceof RingtonePreference) {
            // For ringtone preferences, look up the correct display value
            // using RingtoneManager.
            if (TextUtils.isEmpty(stringValue)) {
                // Empty values correspond to 'silent' (no ringtone).
                preference.setSummary(R.string.pref_ringtone_silent);

            } else {
                Ringtone ringtone = RingtoneManager.getRingtone(
                        preference.getContext(), Uri.parse(stringValue));

                if (ringtone == null) {
                    // Clear the summary if there was a lookup error.
                    preference.setSummary(null);
                } else {
                    // Set the summary to reflect the new ringtone display
                    // name.
                    String name = ringtone.getTitle(preference.getContext());
                    preference.setSummary(name);
                }
            }

        } else {
            // For all other preferences, set the summary to the value's
            // simple string representation.
            preference.setSummary(stringValue);
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setupActionBar();

    }

    /**
     * Set up the {@link android.app.ActionBar}, if the API is available.
     */
    private void setupActionBar() {
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            // Show the Up button in the action bar.
            actionBar.setDisplayHomeAsUpEnabled(true);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean onIsMultiPane() {
        return isXLargeTablet(this);
    }

    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == android.R.id.home) {
            finish();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public void onBuildHeaders(List target) {
        loadHeadersFromResource(R.xml.pref_headers, target);
    }

    /**
     * This method stops fragment injection in malicious applications.
     * Make sure to deny any unknown fragments here.
     */
    protected boolean isValidFragment(String fragmentName) {
        return PreferenceFragment.class.getName().equals(fragmentName)
                || GeneralPreferenceFragment.class.getName().equals(fragmentName)
                || ResetFragment.class.getName().equals(fragmentName)
                || TimeTablePreferenceFragment.class.getName().equals(fragmentName);
    }

    /**
     * This fragment shows general preferences only. It is used when the
     * activity is showing a two-pane settings UI.
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public static class GeneralPreferenceFragment extends PreferenceFragment {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.pref_general);
            setHasOptionsMenu(true);

            /* Bind the summaries of EditText/List/Dialog/Ringtone preferences
             to their values. When their values change, their summaries are
             updated to reflect the new value, per the Android Design
             guidelines.
             bindPreferenceSummaryToValue(findPreference("example_text"));
             bindPreferenceSummaryToValue(findPreference("example_list")); */

            // Allow sync switch
            SettingsActivityServiceAssist sasa = new SettingsActivityServiceAssist();
            sasa.serviceOperationStateListener(findPreference("enable_service"), getActivity().getApplicationContext());

            // Last sync
            EditTextPreference edf = (EditTextPreference) findPreference("lastSync");
            Settings.setContext(getActivity().getApplicationContext());
            SimpleDateFormat sdf = new SimpleDateFormat(Settings.STANDARD_DATE_FORMAT);
            try {
                Date lsd = sdf.parse(Settings.getLastSync());
                Log.v("AAOSyncT","Last sync at "+lsd.getTime());
                edf.setSummary(TimeTeller.getTimeAgo(lsd.getTime()));
            } catch (Exception e)
            {
                edf.setSummary("Chưa đồng bộ lần nào");
            }

            // GradesSync frequency
            ListPreference syncDurationPref = (ListPreference) findPreference("sync_duration");
            int index = syncDurationPref.findIndexOfValue(Settings.getSyncDuration()+"");

            // Set the summary to reflect the new value.
            syncDurationPref.setSummary(
                    index >= 0
                            ? syncDurationPref.getEntries()[index]
                            : null);

            syncDurationPref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
                @Override
                public boolean onPreferenceChange(Preference preference, Object newValue) {
                    // Reset the GradesSync service
                    if(!Settings.getMSSV().equals("undef") && SyncHelper.isNetworkAvailable(getActivity().getApplicationContext()) && Settings.getAllowSync())
                    {
                        SyncHelper.cancelAlarm(getActivity().getApplicationContext());
                        getActivity().getApplicationContext().startService(new Intent(getActivity().getApplicationContext(), SyncOrchestrator.class));
                    }

                    // Bind new value

                    ListPreference listPreference = (ListPreference) preference;
                    int index = listPreference.findIndexOfValue(newValue.toString());

                    // Set the summary to reflect the new value.
                    preference.setSummary(
                            index >= 0
                                    ? listPreference.getEntries()[index]
                                    : null);

                    return true;
                }
            });

            // Edit MSSV
            EditTextPreference mssvPref = (EditTextPreference) findPreference("MSSV");
            mssvPref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
                @Override
                public boolean onPreferenceChange(Preference preference, Object newValue) {
                    GradesHelper gradeMachine = new GradesHelper(getActivity().getApplicationContext());
                    gradeMachine.emptyTable();
                    Settings.setGradeCount(0);
                    return true;
                }
            });

            setSummaryValue(findPreference("MSSV"));
        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            int id = item.getItemId();
            if (id == android.R.id.home) {
                startActivity(new Intent(getActivity(), SettingsActivity.class));
                return true;
            }
            return super.onOptionsItemSelected(item);
        }
    }

    /**
     * This fragment shows TimeTable-related preferences only. It is used when the
     * activity is showing a two-pane settings UI.
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public static class TimeTablePreferenceFragment extends PreferenceFragment {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.pref_timetable);
            setHasOptionsMenu(true);

            // Event handlers
            bindPreferenceSummaryToValue(findPreference("facility"));
            setSummaryValue(findPreference("facility"));

            bindPreferenceSummaryToValue(findPreference("notify_me_before"));
            setSummaryValue(findPreference("notify_me_before"));

        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            int id = item.getItemId();
            if (id == android.R.id.home) {
                startActivity(new Intent(getActivity(), SettingsActivity.class));
                return true;
            }
            return super.onOptionsItemSelected(item);
        }
    }

    /**
     * This fragment shows Reset-related preferences only. It is used when the
     * activity is showing a two-pane settings UI.
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public static class ResetFragment extends PreferenceFragment {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.pref_reset);
            setHasOptionsMenu(true);
            Settings.setContext(getActivity());

            // Reset grades configurations
            Preference gradesPreference = (Preference) findPreference("reset_grades");
            gradesPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
                @Override
                public boolean onPreferenceClick(Preference preference) {
                    confirmAndExecute(new VoidInterface() {
                        @Override
                        public void callback(Object param) {
                            GradesHelper gradesHelper = new GradesHelper(getActivity());
                            gradesHelper.emptyTable();
                            Settings.setGradeCount(0);
                        }
                    });
                    return true;
                }
            });

            // Reset timetable configurations
            Preference timetablePreference = (Preference) findPreference("reset_timetable");
            timetablePreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
                @Override
                public boolean onPreferenceClick(Preference preference) {
                    confirmAndExecute(new VoidInterface() {
                        @Override
                        public void callback(Object param) {
                            SubjectHelper subjectHelper = new SubjectHelper(getActivity());
                            subjectHelper.emptyTable();
                            Settings.resetTimeTableSynced();
                        }
                    });
                    return true;
                }
            });

            // Reset exams configurations
            Preference examPreference = (Preference) findPreference("reset_exams");
            examPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
                @Override
                public boolean onPreferenceClick(Preference preference) {
                    confirmAndExecute(new VoidInterface() {
                        @Override
                        public void callback(Object param) {
                            ExamsHelper examsHelper = new ExamsHelper(getActivity());
                            examsHelper.emptyTable();
                            Settings.setExamsSyncedInvalidate(); // To refresh data the next time ExamsFragment is launched!
                        }
                    });
                    ExamsHelper examsHelper = new ExamsHelper(getActivity());
                    examsHelper.emptyTable();
                    Settings.setExamsSyncedInvalidate(); // To refresh data the next time ExamsFragment is launched!
                    return true;
                }
            });

            // Reset notifications configurations
            Preference notifyPreference = (Preference) findPreference("reset_notify");
            notifyPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
                @Override
                public boolean onPreferenceClick(Preference preference) {
                    confirmAndExecute(new VoidInterface() {
                        @Override
                        public void callback(Object param) {
                            ExamsHelper examsHelper = new ExamsHelper(getActivity());
                            examsHelper.eraseAllExamsNotifiers();
                        }
                    });
                    return true;
                }
            });

            // Reset everything
            Preference allPreference = findPreference("reset_all");
            allPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
                @Override
                public boolean onPreferenceClick(Preference preference) {
                    confirmAndExecute(new VoidInterface() {
                        @Override
                        public void callback(Object param) {
                            GradesHelper gradesHelper = new GradesHelper(getActivity());
                            gradesHelper.emptyTable();
                            Settings.setGradeCount(0);
                            SubjectHelper subjectHelper = new SubjectHelper(getActivity());
                            subjectHelper.emptyTable();
                            Settings.resetTimeTableSynced();
                            ExamsHelper examsHelper = new ExamsHelper(getActivity());
                            examsHelper.emptyTable();
                            Settings.setExamsSyncedInvalidate(); // To refresh data the next time ExamsFragment is launched!
                            examsHelper.eraseAllExamsNotifiers();
                        }
                    });
                    return true;
                }
            });

        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            int id = item.getItemId();
            if (id == android.R.id.home) {
                startActivity(new Intent(getActivity(), SettingsActivity.class));
                return true;
            }
            return super.onOptionsItemSelected(item);
        }

        private void confirmAndExecute(final VoidInterface voidInterface)
        {
            if (voidInterface!=null)
            {
                AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getActivity());

                // set title
                alertDialogBuilder.setTitle("Xác nhận");

                // set dialog message
                alertDialogBuilder
                        .setMessage("Bạn có chắc chắn muốn xóa dữ liệu không? Sau khi xóa, chương trình sẽ tải dữ liệu mới.")
                        .setCancelable(true)
                        .setPositiveButton("CHẮC CHẮN",new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog,int id) {
                                voidInterface.callback(null);
                                new AlertDialog.Builder(getActivity()).setTitle("Hoàn tất").setMessage("Hoạt động mà bạn yêu cầu đã hoàn thành.").setPositiveButton("OK", new DialogInterface.OnClickListener() {
                                    @Override
                                    public void onClick(DialogInterface dialog, int which) {
                                        dialog.cancel();
                                    }
                                }).show();
                            }
                        })
                        .setNegativeButton("THÔI",new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog,int id) {
                                dialog.cancel();
                            }
                        });

                // create alert dialog
                AlertDialog alertDialog = alertDialogBuilder.create();

                // show it
                alertDialog.show();
            }
        }
    }

    /**
     * This fragment shows data and sync preferences only. It is used when the
     * activity is showing a two-pane settings UI.
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    public static class DataSyncPreferenceFragment extends PreferenceFragment {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.pref_data_sync);
            setHasOptionsMenu(true);

            // Bind the summaries of EditText/List/Dialog/Ringtone preferences
            // to their values. When their values change, their summaries are
            // updated to reflect the new value, per the Android Design
            // guidelines.
            bindPreferenceSummaryToValue(findPreference("sync_frequency"));
        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            int id = item.getItemId();
            if (id == android.R.id.home) {
                startActivity(new Intent(getActivity(), SettingsActivity.class));
                return true;
            }
            return super.onOptionsItemSelected(item);
        }
    }
}

redpajama_set_name: RedPajamaGithub


Ask the Professor: Can There be Objective Universal Truth?
"Whether we believe it or not, that higher reality isn't itself abstract; it's concrete. What IS abstract is our knowledge of it. Abstraction is a process our minds engage in, so that we can hold vast amounts of knowledge. When we "abstract," we take all the relevant similarities and differences among concrete things and group them into higher-level concepts."


There was a natural canal across the site. A host of nature diversity.
Local settled down along the canal and built their house with a big terrace by it.
They used this canal as a transportation and living resources.
When city invaded, local moved and the land were sold and combined into a big plot.
Canal was transferred into city drainage and no longer used as transportation and agricultural purposes. Only the trace of a canal across the site remains.
Owner : BTS Sansiri Holding 7 co.,ltd.


text:
Peter Brunholtz: A Biographical Sketch
Charles Porterfield Krauth
Pennsylvania Synod Evangelical Review 1855 / Last updated on 4 Dec 2020 17 min read
How refreshing the thought, that we too, if we are faithful, shall meet and mingle with those who lived and served God in past ages of the church, of whom the world was not worthy; that we shall recognize those whom as Christians we loved on the earth, but whom, as glorified spirits, we shall love still more in heaven.
Introduction: The American Lutheran Founding Fathers
Peter Brunholtz (1724(?)-1758)
Early History
Second Minister to Dr. Muhlenberg
Illness and Passing
His Passing
His Character
"Remember the days of old, consider the years of many generations, ask thy father and he will show thee, thy elders and they will tell thee"
Much has been said, and deservedly, in praise of the Pilgrim Fathers; their memory is properly cherished with veneration, and their virtues earnestly commended for imitation, yet the founders of the American Lutheran Church will not suffer, in any respect, in comparison with them. In piety and zeal they were, by no means, inferior, in education and attainment they were, in many instances, superior. They were men of acknowledged literary character, genuine piety, evangelical sentiment, and ardent attachment to the cause of the Redeemer.
Their Christian heroism, their energetic devotion to the principles they professed, their laborious and self-denying efforts for the salvation of souls and the promotion of God's glory, made a deep impression upon all, with whom they came in contact, and secured the confidence and regard of their contemporaries among other denominations. They were men who could not be despised! They would have adorned the ministry of any church, in whose connection Providence might have placed them. Their character and their works deserve to live in the hearts of posterity. Their virtues and their services should be transmitted to future generations and distant ages. The prevalence of the German language among them in the public worship of the sanctuary, and the preservation of their annals in their native tongue, have deprived them of the position, to which their intellectual and moral qualifications give them a just claim.
Among the most able, faithful, and useful of cur earlier ministers, may be named:
who was the first clergyman sent from Halle, as an assistant to Dr. Muhlenberg, to be associated with him in ministering to the wants of the Lutheran congregation in Pennsylvania.1
He was born in Nübül, a village in the principality of Gluckburg, in the Duchy of Schleswig. He was a candidate of theology when Muhlenberg so earnestly sought for aid in his ministerial labors, and urged the immediate appointment of an associate in the important work, in which he was engaged. He was selected for this purpose by the theological faculty at Halle, with the approbation of all, who were acquainted with his qualifications, and with the state of things in Pennsylvania. He had laid a good foundation in the study of theology at the University, and had already acquired some experience and a practical acquaintance with the duties, to which he had devoted his life.
He had been employed, for some time, to minister in sacred things, on the estates of a Christian nobleman, and in this position had given proofs of his faithfulness, and his gifts in preaching and in the care of souls. When the call from the United States was tendered him, he took the subject into serious and prayerful consideration. The inquiry with him was, "Lord what wilt thou have me to do?" The divine guidance was invoked, and the wisdom which is profitable to direct, was bestowed. His convictions were clear, the path of duty was made plain. He was accordingly, after an examination, invested with the permanent office of the ministry. He was ordained April 12th, 1744, by the Consistorium at Wernigerode, in the chapel of the castle of that place. He immediately made preparations for his departure, and, with Messrs. Kurtz and Schaum, as catechets, embarked for this country at Gravesend, November 29th, 1744. After a long and stormy voyage, they reached Philadelphia in safety, January 26th, 1745.
Their arrival was hailed with great joy. A German coming from the forest, and not knowing who the strangers were, approached them as they were leaving the vessel and going into the city, and inquired whether no evangelical preachers had come to supply their spiritual wants. The answer to the interrogatory was received with unfeigned satisfaction and heartfelt pleasure. They were soon introduced to their brethren of the same faith in Philadelphia, and cordially welcomed to their field of labor. The gratifying intelligence was conveyed by a special messenger to pastor Muhlenberg, who was, at the time, serving his charge in the country. His heart rejoiced, that God had heard his prayer, and granted his request. Between him and Mr. Brunholtz the most tender and intimate friendship existed, so that the latter, when feeble, and almost unable to labor, was wont to say that "he would retire and live as an emeritus with Muhlenberg."
Pastor Brunholtz was appointed second minister in the churches, in which Dr. Muhlenberg had hitherto labored alone, viz: Philadelphia, Germantown, Providence and New Hanover. For these four congregations they jointly performed service. They also proposed to visit other points, in which a prospect of usefulness was presented. The circle of pastoral activity could now be the more readily enlarged, inasmuch as valuable additions had been made to their force in Messrs. Schaum and Kurtz, both of whom assisted in the preaching, and took charge of schools, the former in Philadelphia, and the latter in New Hanover. It was a part of our earlier policy to connect the schoolmaster with the minister in all our congregations. Wherever there was a church, it was the practice of our fathers to plant a school. It was regarded as an important part of our system, to educate the children of the church in the principles of the Christian religion, as well as to furnish them with secular instruction. The beneficial results of such a course were easily apparent; the wisdom of the arrangement none can question. Happy had it been for our communion, if this custom had never been abandoned, if this feature, peculiar to our church, had not been rejected!
After the lapse of a few months, the plan adopted was somewhat modified, and Dr. Muhlenberg assumed the more laborious stations, whilst Philadelphia and Germantown were assigned to the subject of our narrative, as his more immediate charge, in consequence of his physical inability to attend to the duties connected with a residence in the country. He lived in Philadelphia, and preached on the alternate Sabbath, morning and afternoon, in Germantown. Some time after he had entered upon his duties, Dr. Muhlenberg, in a letter dated November 1st 1745, thus speaks of him:
"My dear brother takes heed unto himself, unto the doctrine and the destitute flock. The grace of God is strong in him, notwithstanding his bodily infirmities. He is able to suffer, and yet to fight, to pass through honor, as well as dishonor, through good and evil report, in reliance on that grace. The Lord grants him the favor of the people, and crowneth the word with his blessing,"
In a subsequent communication in the Hallische Nachrichten, he writes:
"Our worthy colleague, Rev. Mr. Brunholtz, has now labored the fifth year with all fidelity and patience in the congregations in Philadelphia and Germantown. He preaches not in the words of human wisdom, but with the demonstration and power of the spirit. His constant aim is the instruction and edification of his hearers. His intercourse with his people is profitable. He is most zealously devoted to their spiritual improvement. He visits the sick by day and by night, if it is necessary, although he is himself in feeble health, and of delicate constitution. He holds special meetings for prayer at his own house. He meditates, prays, and wrestles in his closet for God's blessing upon all the congregations, and especially upon the flock committed to his care, upon the fathers of the church, and the followers of Jesus in Europe. He is much engaged in giving religious instruction to the children. He also takes an interest in the temporal affairs of the church, and sees that pecuniary matters are properly managed, yet as regards his own maintenance, he is easily satisfied. He wants merely a support, and lives from hand to mouth. If there is a surplus, he permits the poor to enjoy it. In all things he proves himself a disciple of God, and a faithful overseer of the mysteries entrusted to his keeping. His labors are not, indeed, without the evidence of the divine blessing. The preached gospel becomes unto some the savor of life unto life."
The favorable testimony to the character and services of Mr. Brunholtz, thus furnished by one who knew him well, and who was closely associated with him in the ministry, is valuable, and is the highest endorsement of his great moral worth and usefulness. Mr. Brunholtz himself thus writes in reference to his congregations, from which some idea may be formed of his spirit, and the deep concern he manifested in the spiritual welfare of his people:2
"As regards the internal condition of my congregations, it is true, the greater number of the old and young are yet under the influence of worldly-mindedness, and in great ignorance, and need a genuine conversion. Nevertheless, there is perceptible in many, an earnest desire to be instructed out of the word of God, and in most, a reverence and devotional attention during the public worship of God; and many manifest a tender love and an abundant confidence towards us, their pastors. There are some, it is true but a few, in both of my congregations, of whom I have a well founded hope, that they have been awakened from the spiritual sleep of sin, and are found under the drawing of the Father to the Son, and who show an earnestness to save their souls; whom to conduct further and to preserve in the wholesome pasture of the word, demand much watchfulness, prayer and divine wisdom."
In a letter written to a friend in Halle in 1752, he also uses the following language:
"I cannot say much in favor of the large body of our people. The Lord has given me a gleaning in some few, who have been influenced by the word to seek the paths of peace, and who are anxious to be prepared for the rest of God. Among our young people I have been able to labor with greater satisfaction. The instructions given them have been peculiarly blessed. Many of our youth take their Bible to church, look for the quoted passages, and give suitable answers to the questions proposed."
In a communication in the Hallische Nachrichten, in 1775, he likewise writes:3
"I find that my catechetical instructions, which I have from the beginning conducted in the church, (to which I have added another exclusively for children on Friday, at my residence) has excited a greater interest not only in the youth of the congregation, but also amongst others, than could be done by preaching alone, because the people are better able to understand instruction in question and answer than in a didactic discourse. These Sabbath afternoon exercises are almost as numerously attended as the services in the morning."
In 1751 Mr. Brunholtz resigned the care of the Germantown church to Mr. Handschuh, and devoted his attention exclusively to the congregation in Philadelphia, although he frequently preached at the other stations. He continued in this charge, until the close of his life, faithfully discharging the duties of his office and universally beloved, not only by the members of his own church, but by the Christian community generally. Whilst pastor in Philadelphia, St. Michael's church was built, the corner stone of which was laid in 1743. The edifice was completed in 1748, and consecrated the same year, during the convention of the first Evangelical Lutheran Synod held in this country.
Mr. Brunholtz's earthly pilgrimage terminated July 7th, 1758. He had been frequently sick, and several times appeared to be on the borders of the grave. He was confined to his bed three months before his death. His sufferings were, however, endured with meekness and Christian fortitude.
Levius fit patentia
Quidquid corrigere est nefas.
Patience makes more tolerable
That which it is impossible to correct. – Horace
No murmur escaped his lips. God was with him in all his trials. They were sanctified to his highest good. His affections became more detached from earth, and ripened for heaven.
"Affliction rightly used
Is mercy in disguise."
"Whom the Lord loveth he chasteneth, and scourgeth every son whom he receiveth,"—"for our profit, that we might be partakers of his holiness." Although apparently very frail he was permitted to labor upwards of thirteen years in Philadelphia, at a period in our history when his services were so much needed, and to accomplish a most important work. His life, it was believed, was at different periods spared in direct answer to fervent intercession, made on his behalf at the throne of grace. His end was such as might have been expected from such a life! In his last hours he was perfectly composed, and willing to leave all with God, happy in the enjoyment of faith in the Redeemer, and simple reliance in the blood of the everlasting covenant.
"Death's terror is the mountain faith removes;
'Tis faith disarms destruction."
Mr. Handschuh writes:
"July 5th, at 2 o'clock, A. M., I was called to Pastor Brunholtz. He wished to speak but could not utter a loud word. With deep sorrow I cast myself upon my knees, and prayed long and fervently. When I arose, I asked him whether he understood all? To which he nodded assent. In a few moments he sank in the embrace of death, amid my renewed and most affectionate supplication."
A large concourse of citizens from town and country attended the funeral ceremonies; several Professors of the Academy, and the ministers of all the churches (fifteen in number) were in attendance. The corpse was interred in the church, in which he had so often delivered God's message. Provost Parlin, of the Swedish Lutheran church, had been requested to preach the funeral sermon, but in consequence of sickness, he was unable to perform the duty. Both Dr. Muhlenberg and pastor Handschuh felt so sad in consequence of their bereavement, that they were incapacitated for the service. William Kurtz, then a student of theology, was therefore asked to prepare a parentation for the occasion, which he accordingly delivered from the words:
"Wherefore, my beloved, as ye have always obeyed, not as in my presence only, but now much more in my absence, work out your own salvation with fear and trembling. For it is God that worketh in you both to will and to do of his good pleasure."
After the delivery of the discourse, Dr. Muhlenberg thanked the English portion of the congregation for the respect they had shown to the dead, and re-conducted, according to custom, the funeral procession to the house of mourning.
Mr. Brunholtz died without family. He was never married. His library he bequeathed to the church, and whatever funds remained, after the settlement of his estate and the payment of some legacies, were to be applied to the erection of a room near the church for the preservation of the books. Very little, however, remained. He had been liberal during his lifetime, and expended his income in doing good, in relieving the wants of the needy, and ministering to the comfort of the suffering. He was distinguished for his large-hearted benevolence. In real kindness of nature and depth and tenderness of feeling, no man surpassed him. It was his happiness to make others happy. No object of benevolence failed to receive his support and encouragement.
Mr. Brunholtz was a man of ardent, consistent piety, and deeply concerned for the salvation of souls. There was nothing extravagant in his religious character, but modest and unassuming, with steady pace he cultivated the path of holiness. His sermons were pungent and of a practical character. They were full of instruction, and abounded with Christian experience. He seemed to have but one object in view — preaching the gospel of the Lord Jesus Christ. "He expounded the word," it is said, "in a clear and simple manner, so that the most illiterate could comprehend the meaning. He adapted his discourses to the condition of the hearers, in order that they might be benefitted by the services."
Individuals of various denominations often attended his preaching. He was not inclined to introduce polemics into the pulpit. He had no taste for controversy. He never went out of his way to attack those who differed from him in sentiment, yet he always presented the truth as it flowed from the text. He frequently cited the writings of Luther in his sermons, in confirmation of his assertions, and showed their correspondence with the word of God. But he did not think that his duties ceased with his labors in the pulpit. He was not satisfied with merely declaring the message in public on the Lord's day, but he sought every opportunity in private, to lead souls to the Savior. He was not only glad to receive the visits of his people, and to talk to them respecting their spiritual condition, but he spent much time in pastoral visitation, going from house, and conversing with his members in reference to the interests of their souls. In this way, he also became thoroughly acquainted with their necessities, and could accommodate his preaching to the state of things that existed.
He was likewise deeply interested in the religious instruction of the children in the congregation, and to them he devoted a considerable portion of his time. This was a prominent feature in the labors of all our earlier ministers, and much is it to be regretted that this characteristic of our church is, at the present day, so sadly disregarded, or performed with so much indifference. If greater attention were bestowed upon the young in the church, and a more earnest interest shown for their recovery from sin, their attachment to the church would be stronger; if they were more thoroughly instructed in the doctrines and practices of the Christian religion, they would, perhaps, find it more difficult to wander from the fold, and in the morning of life would become zealously and faithfully engaged in their Master's service.
Although nearly a century has elapsed since this man of God passed away from earth, his memory is still fragrant. He rests from his labors, but his works do follow him; and, we doubt not, there are multitudes of redeemed spirits, now associated with him in heaven, brought home through his instrumentality, who delight with him, as they cast their crowns at the Savior's feet, to ascribe "blessing, and honor, and glory, and power unto him that sitteth upon the throne, and unto the Lamb for ever and ever." How refreshing the thought, that we too, if we are faithful, shall meet and mingle with those who lived and served God in past ages of the church, of whom the world was not worthy; that we shall recognize those whom as Christians we loved on the earth, but whom, as glorified spirits, we shall love still more in heaven; that in company with them, we shall range over the plains of immortality, in the full radiance of the Redeemer's glory, and together lift up our voices and sing, "Unto him that loved us and washed us from our sins in his own blood, and hath made us kings and priests unto God, to him be glory and dominion for ever and ever."
Reminiscences of Lutheran Ministers Series
"Among our earlier ministers, the fathers of the American Lutheran Church… we can point to many bright names, which Christians of any denomination might be proud to recognize as their own…
"Men distinguished for high talent, great learning, devoted piety, ardent zeal and noble spirit, who were appreciated by their contemporaries, and labored assiduously for the elevation of the race, and the extension of the Redeemer's kingdom." – Charles Krauth
To request a printable copy [PDF] send an email to: editor@lutheranlibrary.org with the title of this post.
Author: "Krauth, Charles P.", Editor.
Journal: "The Evangelical Review."
Lutheran Library Edition: 2019
Copyright: CC BY 4.0
There had been Lutherans in Pennsylvania sixty years anterior to the arrival of Muhlenberg in 1742. They were scattered in different parts of the State, but they were generally without the preached word. A church had been built near Lebanon (the Bergkirche), where the Rev. John Caspar Stoever labored in 1733. There was also one at New Hanover. In Philadelphia the Lutherans worshipped with the German Reformed, in a log house on Arch street. The advent of Dr. Muhlenberg marks a new era in the history of our church in this country. From this period frequent accessions were made to the ranks of the ministry, by men educated at Halle with the highest qualifications for the work, imbued with the missionary spirit, and upon whose labors the blessing of God signally rested. ↩
Hallische Nachrichten, p. 82. See LutheranLibrary.org edition. ↩
Hallische Nachrichten, p. 305. ↩
Michael Eyster: A Biographical Sketch
Michael J. Steck: A Biographical Sketch
Christopher Emanuel Schultze: A Biographical Sketch
John Helfrich Schaum: A Biographical Sketch
David Jacobs: A Biographical Sketch

redpajama_set_name: RedPajamaCommonCrawl


text:
Q: Gutenberg Wordpress: Extending Core Block I am trying to add a padding Inspector Control to all core block of the new Gutenberg Wordpress Editor. I have created the Control on the Editor and now I am trying to apply this style to the block element its self.
But I keep getting This block contains unexpected or invalid content. Error on the blocks. Can anyone help me out here on what exactly I am not doing?
  var paddingEditor = wp.compose.createHigherOrderComponent(function(
    BlockEdit
  ) {
    return function(props) {
      var padding = props.attributes.padding || 0;
      handleChange = name => newValue => {
        if (props) {
          props.setAttributes({ [name]: newValue });
        }
      };
      return el(
        Fragment,
        {},
        el(BlockEdit, props),
        el(
          editor.InspectorControls,
          {},
          el(
            components.PanelBody,
            {
              title: "Padding",
              className: "",
              initialOpen: false
            },
            el("p", {}, "Padding"),
            el(components.TextControl, {
              value: padding,
              onChange: this.handleChange("padding")
            })
          )
        )
      );
    };
  },
  "paddingStyle");

  wp.hooks.addFilter(
    "editor.BlockEdit",
    "my-plugin/padding-style",
    paddingStyle
  );

  function AddPaddingAttribute(element, blockType, attributes) {
    Object.assign(blockType.attributes, {
      padding: {
        type: "string"
      }
    });

    return element;
  }

  wp.hooks.addFilter(
    "blocks.getSaveElement",
    "my-plugin/add-padding-attr",
    AddPaddingAttribute
  );

  function AddPaddingStyle(props, blockType, attributes) {
    if (attributes.padding) {
      props.style = lodash.assign(props.style, { padding: attributes.padding });
    }
    return props;
  }

  wp.hooks.addFilter(
    "blocks.getSaveContent.extraProps",
    "my-plugin/add-background-color-style",
    AddPaddingStyle
  );

PHP
function register_block_extensions(){

    wp_register_script(
        'extend-blocks', // Handle.
        get_template_directory_uri() . '/js/extend-blocks.js',
        array( 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-editor' )
    );
    wp_enqueue_script( 'extend-blocks' );

  }
  add_action('enqueue_block_editor_assets', 'register_block_extensions');

A: Your editor.BlockEdit looks right, but it's hard for me to parse the older syntax. Assuming it is correct, you'll need to replace blocks.getSaveElement with this:
function AddPaddingAttribute(props) {
  if (props.attributes) { // Some modules don't have attributes
    props.attributes = Object.assign(
      props.attributes,
      {
        padding: {}
      }
    );
  }
  return props;
}
wp.hooks.addFilter(
  'blocks.registerBlockType',
  'my-plugin/add-padding-attr',
  AddPaddingAttribute
);

And modify blocks.getSaveContent.extraProps to this:
function AddPaddingStyle(props, blockType, attributes) {
  return Object.assign(
    props,
    {
      style: {
        padding: attributes.padding
      }
    }
  );
}
wp.hooks.addFilter(
  "blocks.getSaveContent.extraProps",
  "my-plugin/add-background-color-style",
  AddPaddingStyle
);

redpajama_set_name: RedPajamaStackExchange


text:
Upgrade Your Off-Road Go Kart Experience
August 13, 2019 by Hammerhead Off-Road
When it comes go go-karts, Hammerhead Off-Road has one of the most premium go-karts in the industry, the GTS Platinum. The GTS Platinum is a off-road go-kart that's suited for people ages 16 and up and offers numerous features that can only be found in a premium go-kart such as the GTS Platinum.
The GTS Platinum is based on our much revered GTS 150 go-kart but outfitted with the premium and luxury features that make the GTS Platinum unique in the hobby of go-karting. Its main feature is that along with the regular Dual-A arm and swing arm suspension system of the GTS 150, the GTS Platinum has nitrogen-gas shocks and this allows the GTS Platinum to have amazing handling off-road as well as on regular paved roads.
That high performance suspension system along with its brushed aluminum wheels and its 149cc 9 horsepower air-cooled 4-stroke engine means that the GTS Platinum will allow its driver and occupant to have the most fun they can have on a go-kart, whether they're on a race track or off-road. The GTS Platinum is a very safe go-kart too, and it has the premium safety features to show for it. With both front and rear hydraulic disk brakes, the GTS Platinum can come to a stop safely and quickly.
On top of that, its protective brush guards and its five-point sports-style safety harness will provide great amounts of protection and safety to the driver and the occupant of the GTS Platinum. In addition to that, the GTS Platinum has other useful features such as dual headlights, a digital speedometer, and a canopy that can be retracted to cover the top of the go-kart.
If the GTS Platinum sounds like the premium go-kart for you, please contact us for more information or click here to find a dealer near you.
The HH Torpedo™, the Best Go-Kart for Kids
3 Fun Karts for Kids of Every Age


text:
June 15 2017 // Work
When is the last time you ventured out for a little bit of Iowa learning?
This year marks the first year of the now annual Iowa Museum Week, and we're smack dab in the middle of it. The state of Iowa boasts approximately 400 museums. Big and small, indoors or out, there's a lot to see and a lot to learn, and at many of Iowa's Museums, you can learn more by exploring interactive exhibits built by your pals at Applied Art & Technology!
Here's a rundown of a few of our favorites!
1. The Sullivan Brothers Iowa Veterans Museum, Waterloo, Iowa
The mission of the Sullivan Brothers Iowa Veterans Museum is the collection, preservation, and interpretation of Iowa veteran experiences and the contributions made by civilians on the homefront.
Applied Art worked with the museum team and their designer/fabricator, Split Rock Studios, to plan the exhibit computer interactives. We provided content development, production and integration services for:
35 documentaries and/or veteran interviews
78 homefront and warfront stories
7 interactive "Dog Tag" stations
2 veteran Search Stations
A memorial tribute to Iowa KIA/MIAs A laser-based WWII chronology
2. Carrie Chapman Catt Museum, St. Charles, Iowa
Women's right to vote and run for office are largely attributed to Carrie Chapman Catt's efforts during the early twentieth century. Her girlhood home on a farm southeast of Charles City, Iowa, is now a museum in her honor.
A multi-touch table that allows several visitors to interact simultaneously, was developed by Applied Art & Technology in conjunction with the museum staff.
The multi-touch table's presence in the midst of historical information and artifacts creates a contrast that engages visitors of all ages. The fusion of technology and history shows that individuals can make a difference no matter their beginnings, as demonstrated by Catt's contributions toward advancing rights for women.
3. Danish Modern & Victor Borge Interactives
The Museum of Danish America's Danish Modern: Design for Living exhibit features design from the 50s and 60s with characteristics including a fusion of form and function along with flawless craftsmanship.
The Danish Design Today interactive is a 32" touchscreen with an integrated computer that features six Danish designers. Touching the screen replaces the looping attract video with a menu. Tapping a title launches the playback of the featured video.
A 46" Danish Design electronic gallery cycles through images highlighting Danish Modern design.
The museum's Victor Borge interactive features a small touchscreen kiosk – styled to resemble a music stand – located next to Mr. Borge's grand piano on the museum's main floor.
4. German American Heritage Center, Davenport, IA
The German American Heritage Center in Davenport, Iowa, immerses visitors in 100 years of the German immigrant experience.
Ambient audio enhances two areas of the exhibit that transport visitors from a dock in Hamburg into a new world.
The Step Into My Shoes interactive lets visitors to actually step onto the footprints of a man, a woman, or a child to launch videos describing each person's journey or experiences in America.
The Party Line Interactive consists of three "party line" telephones that allow the visitor to pick up and eavesdrop on immigrant conversations highlighting the suppression of German culture and language, and the tensions between the immigrants and other citizens.
The Scheutzenpark Festival game simulates festival activities at Scheutzenpark – a gathering spot for immigrant families. A trolley ride "quiz" tells about immigrant life. Crossbow shooting for the boys or pottery smashing for the girls earns each contestant a title – from king or queen to serf or queen's court
5. University of Iowa: Old Capitol Museum
University of Iowa's Old Capitol Museum, in cooperation with the University Library, was exploring ways to share historic children's diaries with visitors to the museum.
To provide as realistic visitor experience as possible, we suggested creating mock books that, when inserted into a slot, displayed the contents of the diary on the adjacent LCD panel.
Visitors choose to view images of actual handwritten diary pages or easier-to-read transcripts, and can also learn more about the autobiographer and the era.
6. Iowa Hall of Pride, Des Moines, Iowa
The Iowa Hall of Pride is an interactive museum celebrating students who excelled in sport, on the stage, and as great ambassadors of their communities. Applied Art & Technology developed four key interactives featured at the Iowa Hall of Pride.
You Make the Call is an immersive experience that puts the visitor in the umpire's shoes, calling 90-mph curveballs and experiencing crowd reactions – good and bad. The player views pitches through stereoscopic monitors within an umpire's mask while spectators watch the action in projected high-definition video.
The All-State Music Festival takes place every year. Six-hundred-fifty of the state's best high school musicians are selected to perform at the All-State Music Festival.
Applied Art captured on of these performances – in full HD video and surround sound – simultaneously from 3 different points of view:
The audience. The choir. The orchestra.
As visitors experience this performance, they can switch from one perspective to another in real time using a separate touchscreen interface. A second activity provides the opportunity to sing-along to all-time favorite songs.
To create the High School Kiosks, three years before the Iowa Hall of Pride was to open, Applied Art developed a web-based Content Management System (CMS), along with a user's guide and introductory video that we distributed to 403 high schools across the state.
High school students, historians, and other interested participants used the CMS to upload photos, stories, videos, school songs, district maps, trivia questions and a wealth of information about their communities and schools.
You're The Ref is a multi-player game. Four visitors try to accurately score a high school wrestling match in real time, awarding points to the red and green wrestlers for takedowns, near falls, escapes and reversals.
When a wrestler scores, the visitor awards points using hotspots on a touchscreen. At the end of the match, visitors compare their points awarded to the official score. Players receive or lose game points based on the speed and accuracy of their calls.
Iowa Museum Week continues through June 18th...but really, any time is a good time to do a little learning about our great state. Need ideas for your next interactive project? Let us know!
Courtnee Carstens
Interactive Kiosks Museum
The Vein Center at Iowa Heart will be one of a few local companies who will be running HD commercials during this yea... read more


Welcome! I'm Jana, a portrait photographer from Spring TX! I love big smiles, music, and lots of chocolate!
Most days you can find me playing guitar, singing, and drinking way too much coffee with my sweet firefighter hubby!
I picked up a camera when I was 13, and I've been taking pictures ever since. I believe in finding beauty in the ordinary, and capturing authenticity. I love taking photos because I love telling a story!


text:
Antipsychotic drugs, such as haloperidol (HAL), are prescribed in the clinic to manage traumatic brain injury (TBI)-induced agitation. While preclinical studies have consistently shown that once-daily administration of HAL hinders functional recovery after TBI in male rats, its effects in females are unknown. Hence, the objective of this study was to directly compare neurobehavioral and histological outcomes in both sexes to determine whether the reported deleterious effects of HAL extend to females. Anesthetized adult female and male rats received either a controlled cortical impact (CCI) or sham injury and then were randomly assigned to a dosing regimen of HAL (0.5mg/kg, i.p.) or vehicle (VEH; 1mL/kg, i.p.) that was initiated 24h after injury and continued once daily for 19 consecutive days. Motor function was tested using established beam-balance/walk protocols on post-operative days 1-5 and acquisition of spatial learning was assessed with a well-validated Morris water maze task on days 14-19. Cortical lesion volume was quantified at 21days. No statistical differences were revealed between the HAL and VEH-treated sham groups and thus they were pooled for each sex. HAL only impaired motor recovery in males (p
Comparable impediment of cognitive function in female and male rats subsequent to daily administration of haloperidol after traumatic brain injury.


This guest post was contributed by Slava Chernikoff (Principal Engineer at Binwell, Microsoft MVP, Xamarin Certified Mobile Developer), Artem Tischenko (Xamarin developer at Binwell) and Kirill Ashikhmin (Xamarin and Android developer at Binwell).
Binwell's team members have a long history of using Xamarin and were very excited to adopt Xamarin.Forms 1.0 for real projects. One day in 2015, we got a task to make a mobile marketplace application. An application that should have a complex user interface with many different components and a large product data set.
This application should be able to display hundreds of products, banners and other controls on one page. There should be an almost infinite scrolling with many products, banners, special sections (favorite, discounted items, etc). That was the beginning of our story to adopting Android RecyclerView and iOS UICollectionView for Xamarin.Forms.
In this article, we will focus on one of our favorite projects: Instamart grocery delivery service for Russian customers. Here are screenshots of the current Instamart application based on Xamarin.Forms and Binwell FastGrid.
Notes: We are very excited with Xamarin.Forms evolution and the upcoming Xamarin.Forms 4.0. New CollectionView. FastGrid was created for another set of tasks and distributed 'as is'.
This article will show how to use FastGrid for complex user interfaces with many cell view types. Binwell FastGrid can be adopted by teams with native experience and used as a customizable white box component.
When we started our research on Xamarin.Forms controls for complex UI, our first thought was using Grid and Stack Layouts. Obviously, performance was very poor because these layouts were created for another task. The main drawback of layout components is that they don't reuse child views while creating all of the views when the layout is displayed. That is why it can be near impossible to deal with a large number of child views with Grid, StackLayout, etc.
As a second step, we tried to use the default ListView component to display a number of cells in one row. It was much better than using Layouts (including a 3rd party RepeaterView), however, it still had performance drawbacks and issues with scrolling. Horizontal scroll implementation inside a row was a bit tricky, while vertical scrolling lagged on low-end Android devices. So we continued our research.
We tried a number of commercial Xamarin.Forms components based on RecyclerView/UICollectionView, though most of them were limited and didn't provide the necessary functionality.
TwinTechs FastGrid implementation was very promising. Although it didn't work on Android and had a lot of limitations out-of-box, it was a great starting point. We used this FastGrid control as a white box (just add files directly to project) and improved significantly over the last 3 years. Many thanks to TwinTechs for such a great idea and implementation!
First, our goal was an implementation of a complex user interface for our client's application. We didn't try to implement a universal CollectionView component for all possible cases and scenarios. Instead, we just tried to get a single result and it worked! Slava Chernikoff was focused on iOS implementation, and later Kirill Ashikhmin adopted it for Android.
Let us remind you of the task at hand – getting a complex UI with many different view types, horizontal scrolling, and the fastest possible vertical scrolling. It also had to be data driven from a backend API (show and hide views depending on data models received from the backend).
The first point was to achieve maximum scrolling performance. Leading us to skip dynamic cell sizing and use hard-coded width/height for every ViewCell type. The second point was handling many cell types. Which is why we used DataTemplateSelector for all of these tasks.
The diagram above demonstrates using of DataTemplateSelector for making a complex UI based on data from backend API.
To demonstrate the usage of Binwell FastGrid, let's start with a common mobile marketplace case: displaying a grouped products list in 2 columns.
As you can see, you should implement custom InitializeCell() and SetupCell() methods. The example above demonstrates code-behind UI creation, but you can also use XAML and Bindings by placing InitializeComponent() inside InitializeCell(). Additionally, you can use the SetupCell() method for manually setting of new values. In some cases it lets you fine-tune your data or UI.
Create a new FastGridDataTemplate to configure a relationship between the model (data object) and view types. As mentioned earlier, to speed up the scrolling performance we set exact view sizes depending on model type. It's not very flexible, but also does not require heavy cell size calculations.
Android RecyclerView requires integer numbers to identify different view types. That is why FastGridTemplateSelector use Prepare() method to populate a DataTemplateViewTypes dictionary. Below you can see more samples of using FastGrid.
Many thanks for TwinTechs for initial project and ideas!