Create flutter apps quickly by utilizing commonly used tools.
The aim of this package is to make building apps quick and seamless, incorperating some frequently used widgets in app development.
Getting started
- add package
flutter pub add close_range_util
- Inside your main function when you call runApp, pass in an
Entry
object
runApp(Entry(
title: "Testing 123",
home: MyFirstPage(...), // Widget of inital page page
));
The point of this is to allow for global bindings such as themes to the whole project.
Setup
Some features require an initilization phase.
This can be done right inside of main before calling runApp
For example:
void main() async {
await CREnv.init();
await CRSave.init();
await CRDatabase.init(
url: CREnv["SUPABASE_URL"]!,
anonKey: CREnv["SUPABASE_ANON_KEY"]!,
);
Debug.setActive(false);
runApp(...);
}
Features
Login
Signup
Documentation
App Bar
Calendar
Debug Page
Settings
Region
Profile Picture
Profile Banner
Systems
Enviroment
Save System
User
Database
Debug
Theme
Login
Signup
Docs
Docs is a way to easily integrate a documentation page into your flutter apps. This can help users of your app learn more about how it works.
App Bar
Calendar
Debug Page
Settings
Region
Profile Picture
Profile Banner
Enviroment
Enviroment or CREnv
is a way to grab enviroment variables out of a file.
This is a direct mirror of the Env
package.
Initialize
Before calling runApp
ensure you initilize the enviroment
This takes a parameter for the name of the enviroment file, but can be ommitted for the default file name of .env
void main() async {
await CREnv.init();
runApp(...);
}
Creating the file
By default the naem of the file is .env
but can be changed as a parameter inside the init function.
The file consists of key value pairs such as:
DATABASE_PASSWORD = "..."
FIREBASE_SENDER_ID = "..."
Getting data
CREnv["env_name"];
Save System
The Save system or CRSave
is a way to save data to and from the device. It's a wrapper around SharedPreferences
Initialize
Before calling runApp
ensure you initilize the save system:
void main() async {
await CRSave.init();
runApp(...);
}
Save / Load
To save and load data to the device simply call save/load providing the variable key.
The load method takes a default value in case the value has yet to be saved into memory.
CRSave.save<int>("myValue", 123);
int v = CRSave.load<int>("myValue", 0);
Clearing data
You can either clear a single key, or clear all data:
await CRSave.clear("myValue");
await CRSave.clearAll();
Binding
Binding to the save system allows you to easily track variables that have changed.
CRSave.bind(
key: "myValue",
defaultValue: 0,
builder: (val) => Text(val.toString())
);
User
The user system controls who is logged in currently to an account and is completly depends on the Database system.
Initalize
Before using the user system, you need to initalize supabase
inside the main method
void main() async {
await CRDatabase.init(
url: CREnv["SUPABASE_URL"]!,
anonKey: CREnv["SUPABASE_ANON_KEY"]!,
);
runApp(...);
}
Supabase Setup
inside supabase itself, you will need to Enable Phone Provider
inside the authentication.
You will also need a table named users
with at least the following columns:
user_id
-> uuidpfp
-> textfirst_name
-> textlast_name
-> text You can provide more columns as well and they will be retrivable directly from the user object
Logging in
To log into an account provide either the phonenumber or email (but not both):
CRUser? user =
await CRUser.attemptLogin(phone: phone, password: pass);
if(user == null) {...} // invalid credentials
Once logged in you can retrieve any data from the provided user:
user["myColumn"];
user.getValue("myColumn");
When saving, you must provide a map of all values you want to change:
await user.setValue({
"myColumn": 25
});
By default it will automatically save directly to supabase, but you can set the save
parameter to false to only save locally.
Current User
When logging in you don't need to save the provided user, simply get it statically CRUser.current
Loading User
You can load a user and their details without actually logging in:
CRUser? user = await CRUser.load(uuid);
Reloading User
Sometimes you may need to refetch the data from a user and update the values:
await user.reload();
await CRUser.current!.reload();
Binding
You can bind widgets to the user in order to track changes made.
To do this simply call bind
from the user in question:
CRUser.current!.bind(
builder: (user) => Text(user.firstName)
);
Replication
When binding a widget (see above) you can choose to use replication, which will track changes to the database itself rather than tracking the local copy.
In supabase, edit the users
database and enable replication.
Then set replication to true
CRUser.current!.bind(
replication: true,
builder: (user) => Text(user.firstName)
);
NOTE: This will turn off the default binding, so any bindings will only update if the database itself is modified.
Database
the database system lets you easily use supabase with little work.
Initialize
Before using the database, call the init function
void main() async {
await CRDatabase.init(
url: CREnv["SUPABASE_URL"]!,
anonKey: CREnv["SUPABASE_ANON_KEY"]!,
);
runApp(...);
}
The CREnv is a nicer way to store the url and anon key from supabase
Timing
When calling most functions from the database, a fixed delay is added to test out lag within the calls.
This is only active when Debug is active.
You can access the delay manually as well by calling it
await CRDatabase.delay;
Supabase Raw
You can access any supabase function by simply grabbing the auth or client
CRDatabase.client...
CRDatabase.auth...
CRDatabase.getClient()...
CRDatabase.getAuth()...
using the get functions will also add the delay into the calls where getting the raw values will ommit the delay
Getting Data
The easist way to get data is with one of 2 ways:
CRDatabase.select(table, [columns])
CRDatabase.selectEq(table, column, value, [columns])
Where[columns]
is"*"
by default (select all)
Setting Data
For setting data you can insert, update, or delete:
CRDatabase.insert(table, values)
CRDatabase.update(table, values)
CRDatabase.delete(table, column, value)
For insert and update take in a map of string value pairs.
Delete takes a column name and a value to compare to and will delete any entry where the value = column
Debug
Debug is simply a way to log messages and have them show in app.
Enabling
You can check if debug mode is on by using Debug.active
You can disable debug mode with either setActive
or setReleaseMode
Debug.active; // true by default
Debug.releaseMode; // true by default
Debug.setActive(false); // Turns debug off
Debug.setReleaseMode(false); // will also make active false
Debug.toggleDebug();
Release Mode
Sometimes you may want to be able to disable or enable debug mode on the fly while testing.
Release mode is meant to be a way to fully disable debug mode, so if release mode is active, you can never turn debug mode on.
Database Delay
Inside Database any calls you make have an automatic delay of 3 seconds if debug mode is active.
This delay can be turned off or changed
Debug.setSqlDelay(false); // turns delay off
Debug.setSqlDelayTime(5000); // sets delay to 5 seconds
Debug Messages
You can also write debug messages that will show up in the Debug Page rather than the console.
Debug.log(message, [inner]);
Debug.warn(message, [inner]);
Debug.error(message, [inner]);
Debug.clearLog();
Theme
Themes is an easy way to change the color of the app.
Initialize
While there is no setup needed for themes directly, you will need to initialize the Save System first
void main() async {
await CRSave.init();
runApp(...);
}
Set Theme
To set a them simply call setTheme or setDark
CRTheme.setTheme(CRThemeType.sakura);
CRTheme.setDark(true);
This will automatically save the theme as well for the next time you open the app
Theme Settings
Within the Settings api there is also an option to create a atuo theme selector and dark mode selector:
CRSettings.colorTheme(context);
CRSettings.darkMode(context);